pax_global_header00006660000000000000000000000064122342344070014513gustar00rootroot0000000000000052 comment=674e0683064b3e5c105447a0fd3b185a97208650 libsepol-2.2/000077500000000000000000000000001223423440700131675ustar00rootroot00000000000000libsepol-2.2/.gitignore000066400000000000000000000000151223423440700151530ustar00rootroot00000000000000utils/chkcon libsepol-2.2/Android.mk000066400000000000000000000034561223423440700151100ustar00rootroot00000000000000LOCAL_PATH:= $(call my-dir) common_src_files := \ src/assertion.c \ src/avrule_block.c \ src/avtab.c \ src/boolean_record.c \ src/booleans.c \ src/conditional.c \ src/constraint.c \ src/context.c \ src/context_record.c \ src/debug.c \ src/ebitmap.c \ src/expand.c \ src/genbools.c \ src/genusers.c \ src/handle.c \ src/hashtab.c \ src/hierarchy.c \ src/iface_record.c \ src/interfaces.c \ src/link.c \ src/mls.c \ src/module.c \ src/node_record.c \ src/nodes.c \ src/polcaps.c \ src/policydb.c \ src/policydb_convert.c \ src/policydb_public.c \ src/port_record.c \ src/ports.c \ src/roles.c \ src/services.c \ src/sidtab.c \ src/symtab.c \ src/user_record.c \ src/users.c \ src/util.c \ src/write.c common_cflags := \ -Wall -W -Wundef \ -Wshadow -Wmissing-noreturn \ -Wmissing-format-attribute ifeq ($(HOST_OS), darwin) common_cflags += -DDARWIN endif common_includes := \ $(LOCAL_PATH)/include/ \ $(LOCAL_PATH)/src/ ## # libsepol.so # include $(CLEAR_VARS) LOCAL_MODULE := libsepol LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) LOCAL_CFLAGS := $(common_cflags) LOCAL_SRC_FILES := $(common_src_files) LOCAL_MODULE_CLASS := SHARED_LIBRARIES include $(BUILD_HOST_SHARED_LIBRARY) ## # libsepol.a # include $(CLEAR_VARS) LOCAL_MODULE := libsepol LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) LOCAL_CFLAGS := $(common_cflags) LOCAL_SRC_FILES := $(common_src_files) LOCAL_MODULE_CLASS := STATIC_LIBRARIES include $(BUILD_HOST_STATIC_LIBRARY) ## # chkcon # include $(CLEAR_VARS) LOCAL_MODULE := chkcon LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) LOCAL_CFLAGS := $(common_cflags) LOCAL_SRC_FILES := utils/chkcon.c LOCAL_SHARED_LIBRARIES := libsepol LOCAL_MODULE_CLASS := EXECUTABLES include $(BUILD_HOST_EXECUTABLE) libsepol-2.2/COPYING000066400000000000000000000635001223423440700142260ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libsepol-2.2/ChangeLog000066400000000000000000000611321223423440700147440ustar00rootroot000000000000002.2 2013-10-30 * Allow constraint denial cause to be determined from Richard Haines. - Add kernel policy version 29. - Add modular policy version 17. - Add sepol_compute_av_reason_buffer(), sepol_string_to_security_class(), sepol_string_to_av_perm(). * Support overriding Makefile RANLIB from Sven Vermeulen. * Fix man pages from Laurent Bigonville. 2.1.9 2013-02-01 * filename_trans: use some better sorting to compare and merge * coverity fixes * implement default type policy syntax * Fix memory leak issues found by Klocwork 2.1.8 2011-09-13 * fix neverallow checking on attributes * Move context_copy() after switch block in ocontext_copy_*(). * check for missing initial SID labeling statement. * Add always_check_network policy capability * role_fix_callback skips out-of-scope roles during expansion. 2.1.7 2011-06-28 * reserve policycapability for redhat testing of ptrace child * cosmetic changes to make the source easier to read * prepend instead of append to filename_trans list * Android/MacOS X build support 2.1.6 2011-04-23 * allocate enough space to hold filename in trans rules 2.1.5 2011-03-28 * checkpolicy: implement new default labeling behaviors 2.1.4 2011-10-03 * regenerate .pc on VERSION change * Move ebitmap_* functions from mcstrans to libsepol * expand: do filename_trans type comparison on mapped representation 2.1.3 2011-09-15 * Skip writing role attributes for policy.X and * Indicate when boolean is indeed a tunable. * Separate tunable from boolean during compile. * Write and read TUNABLE flags in related * Copy and check the cond_bool_datum_t.flags during link. * Permanently discard disabled branches of tunables in * Skip tunable identifier and cond_node_t in expansion. * Create a new preserve_tunables flag * Preserve tunables when required by semodule program. * setools expects expand_module_avrules to be an exported * tree: default make target to all not 2.1.2 2011-08-03 * Only call role_fix_callback for base.p_roles during expansion. * use mapped role number instead of module role number 2.1.1 2011-08-01 * Minor fix to reading policy with filename transition rules 2.1.0 2011-07-27 * Release, minor version bump 2.0.46 2011-07-25 * Add role attribute support by Harry Ciao 2.0.45 2011-05-02 * Warn if filename_trans rules are dropped by Steve Lawrence. 2.0.44 2011-04-13 * Fixes for new role_transition class field by Eric Paris. * Add libsepol support for filename_trans rules by Eric Paris. 2.0.43 2011-04-11 * Add new class field in role_transition by Harry Ciao. 2.0.42 2010-12-16 * Fix compliation under GCC 4.6 by Justin Mattock 2.0.41 2009-11-18 * Fixed typo in error message from Manoj Srivastava. 2.0.40 2009-10-29 * Add pkgconfig file from Eamon Walsh. 2.0.39 2009-10-14 * Add support for building Xen policies from Paul Nuzzi. 2.0.38 2009-09-01 * Check last offset in the module package against the file size. Reported by Manoj Srivastava for bug filed by Max Kellermann. 2.0.37 2009-07-07 * Add method to check disable dontaudit flag from Christopher Pardy. 2.0.36 2009-03-25 * Fix boolean state smashing from Joshua Brindle. 2.0.35 2009-02-19 * Fix alias field in module format, caused by boundary format change from Caleb Case. 2.0.34 2008-10-09 * Add bounds support from KaiGai Kohei. * Fix invalid aliases bug from Joshua Brindle. 2.0.33 2008-09-29 * Revert patch that removed expand_rule. 2.0.32 2008-07-07 * Allow require then declare in the source policy from Joshua Brindle. 2.0.31 2008-06-13 * Fix mls_semantic_level_expand() to handle a user require w/o MLS information from Stephen Smalley. 2.0.30 2008-06-06 * Fix endianness bug in the handling of network node addresses from Stephen Smalley. Only affects big endian platforms. Bug reported by John Weeks of Sun upon policy mismatch between x86 and sparc. 2.0.29 2008-05-27 * Merge user and role mapping support from Joshua Brindle. 2.0.28 2008-05-05 * Fix mls_level_convert() to gracefully handle an empty user declaration/require from Stephen Smalley. 2.0.27 2008-04-18 * Belatedly merge test for policy downgrade from Todd Miller. 2.0.26 2008-03-24 * Add permissive domain support from Eric Paris. 2.0.25 2008-03-04 * Drop unused ->buffer field from struct policy_file. 2.0.24 2008-03-04 * Add policy_file_init() initalizer for struct policy_file and use it, from Todd C. Miller. 2.0.23 2008-02-28 * Accept "Flask" as an alternate identifier string in kernel policies from Stephen Smalley. 2.0.22 2008-02-28 * Add support for open_perms policy capability from Eric Paris. 2.0.21 2008-02-20 * Fix invalid memory allocation in policydb_index_others() from Jason Tang. 2.0.20 2008-02-04 * Port of Yuichi Nakamura's tune avtab to reduce memory usage patch from the kernel avtab to libsepol from Stephen Smalley. 2.0.19 2008-02-02 * Add support for consuming avrule_blocks during expansion to reduce peak memory usage from Joshua Brindle. 2.0.18 2008-01-02 * Added support for policy capabilities from Todd Miller. 2.0.17 2007-12-21 * Prevent generation of policy.18 with MLS enabled from Todd Miller. 2.0.16 2007-12-07 * print module magic number in hex on mismatch, from Todd Miller. 2.0.15 2007-11-29 * clarify and reduce neverallow error reporting from Stephen Smalley. 2.0.14 2007-11-05 * Reject self aliasing at link time from Stephen Smalley. 2.0.13 2007-11-05 * Allow handle_unknown in base to be overridden by semanage.conf from Stephen Smalley. 2.0.12 2007-10-11 * Fixed bug in require checking from Stephen Smalley. * Added user hierarchy checking from Todd Miller. 2.0.11 2007-09-24 * Pass CFLAGS to CC even on link command, per Dennis Gilmore. 2.0.10 2007-09-18 * Merged support for the handle_unknown policydb flag from Eric Paris. 2.0.9 2007-08-29 * Moved next_entry and put_entry out-of-line to reduce code size from Ulrich Drepper. 2.0.8 2007-08-28 * Fixed module_package_read_offsets bug introduced by the prior patch. 2.0.7 2007-08-23 * Eliminate unaligned accesses from policy reading code from Stephen Smalley. 2.0.6 2007-08-16 * Allow dontaudits to be turned off during policy expansion from Joshua Brindle. 2.0.5 2007-08-01 * Fix sepol_context_clone to handle a NULL context correctly. This happens for e.g. semanage_fcontext_set_con(sh, fcontext, NULL) to set the file context entry to "<>". 2.0.4 2007-06-20 * Merged error handling patch from Eamon Walsh. 2.0.3 2007-04-13 * Merged add boolmap argument to expand_module_avrules() from Chris PeBenito. 2.0.2 2007-03-30 * Merged fix from Karl to remap booleans at expand time to avoid holes in the symbol table. 2.0.1 2007-02-06 * Merged libsepol segfault fix from Stephen Smalley for when sensitivities are required but not present in the base. 2.0.0 2007-02-01 * Merged patch to add errcodes.h to libsepol by Karl MacMillan. 1.16.0 2007-01-18 * Updated version for stable branch. 1.15.3 2006-11-27 * Merged patch to compile wit -fPIC instead of -fpic from Manoj Srivastava to prevent hitting the global offest table limit. Patch changed to include libselinux and libsemanage in addition to libselinux. 1.15.2 2006-10-31 * Merged fix from Karl MacMillan for a segfault when linking non-MLS modules with users in them. 1.15.1 2006-10-24 * Merged fix for version comparison that was preventing range transition rules from being written for a version 5 base policy from Darrel Goeddel. 1.14 2006-10-17 * Updated version for release. 1.12.28 2006-09-28 * Build libsepol's static object files with -fpic 1.12.27 2006-09-28 * Merged mls user and range_transition support in modules from Darrel Goeddel 1.12.26 2006-09-05 * Merged range transition enhancements and user format changes Darrel Goeddel 1.12.25 2006-08-24 * Merged conditionally expand neverallows patch from Jeremy Mowery. * Merged refactor expander patch from Jeremy Mowery. 1.12.24 2006-08-03 * Merged libsepol unit tests from Joshua Brindle. 1.12.23 2006-08-03 * Merged symtab datum patch from Karl MacMillan. 1.12.22 2006-08-03 * Merged netfilter contexts support from Chris PeBenito. 1.12.21 2006-07-28 * Merged helpful hierarchy check errors patch from Joshua Brindle. 1.12.20 2006-07-25 * Merged semodule_deps patch from Karl MacMillan. This adds source module names to the avrule decls. 1.12.19 2006-06-29 * Lindent. 1.12.18 2006-06-26 * Merged optionals in base take 2 patch set from Joshua Brindle. 1.12.17 2006-05-30 * Revert 1.12.16. 1.12.16 2006-05-30 * Merged cleaner fix for bool_ids overflow from Karl MacMillan, replacing the prior patch. 1.12.15 2006-05-30 * Merged fixes for several memory leaks in the error paths during policy read from Serge Hallyn. 1.12.14 2006-05-25 * Fixed bool_ids overflow bug in cond_node_find and cond_copy_list, based on bug report and suggested fix by Cedric Roux. 1.12.13 2006-05-24 * Merged sens_copy_callback, check_role_hierarchy_callback, and node_from_record fixes from Serge Hallyn. 1.12.12 2006-05-22 * Added sepol_policydb_compat_net() interface for testing whether a policy requires the compatibility support for network checks to be enabled in the kernel. 1.12.11 2006-05-17 * Merged patch to initialize sym_val_to_name arrays from Kevin Carr. Reworked to use calloc in the first place, and converted some other malloc/memset pairs to calloc calls. 1.12.10 2006-05-08 * Merged patch to revert role/user decl upgrade from Karl MacMillan. 1.12.9 2006-05-08 * Dropped tests from all Makefile target. 1.12.8 2006-05-05 * Merged fix warnings patch from Karl MacMillan. 1.12.7 2006-05-05 * Merged libsepol test framework patch from Karl MacMillan. 1.12.6 2006-04-28 * Fixed cond_normalize to traverse the entire cond list at link time. 1.12.5 2006-04-03 * Merged fix for leak of optional package sections from Ivan Gyurdiev. 1.12.4 2006-03-29 * Generalize test for bitmap overflow in ebitmap_set_bit. 1.12.3 2006-03-27 * Fixed attr_convert_callback and expand_convert_type_set typemap bug. 1.12.2 2006-03-24 * Fixed avrule_block_write num_decls endian bug. 1.12.1 2006-03-20 * Fixed sepol_module_package_write buffer overflow bug. 1.12 2006-03-14 * Updated version for release. 1.11.20 2006-03-08 * Merged cond_evaluate_expr fix from Serge Hallyn (IBM). * Fixed bug in copy_avrule_list reported by Ivan Gyurdiev. 1.11.19 2006-02-21 * Merged sepol_policydb_mls_enabled interface and error handling changes from Ivan Gyurdiev. 1.11.18 2006-02-16 * Merged node_expand_addr bugfix and node_compare* change from Ivan Gyurdiev. 1.11.17 2006-02-15 * Merged nodes, ports: always prepend patch from Ivan Gyurdiev. * Merged bug fix patch from Ivan Gyurdiev. 1.11.16 2006-02-14 * Added a defined flag to level_datum_t for use by checkpolicy. 1.11.15 2006-02-14 * Merged nodecon support patch from Ivan Gyurdiev. * Merged cleanups patch from Ivan Gyurdiev. 1.11.14 2006-02-13 * Merged optionals in base patch from Joshua Brindle. 1.11.13 2006-02-07 * Merged seuser/user_extra support patch from Joshua Brindle. * Merged fix patch from Ivan Gyurdiev. 1.11.12 2006-02-02 * Merged clone record on set_con patch from Ivan Gyurdiev. 1.11.11 2006-02-01 * Merged assertion copying bugfix from Joshua Brindle. * Merged sepol_av_to_string patch from Joshua Brindle. 1.11.10 2006-01-30 * Merged cond_expr mapping and package section count bug fixes from Joshua Brindle. * Merged improve port/fcontext API patch from Ivan Gyurdiev. * Merged fixes for overflow bugs on 64-bit from Ivan Gyurdiev. 1.11.9 2006-01-12 * Merged size_t -> unsigned int patch from Ivan Gyurdiev. 1.11.8 2006-01-09 * Merged 2nd const in APIs patch from Ivan Gyurdiev. 1.11.7 2006-01-06 * Merged const in APIs patch from Ivan Gyurdiev. * Merged compare2 function patch from Ivan Gyurdiev. 1.11.6 2006-01-06 * Fixed hierarchy checker to only check allow rules. 1.11.5 2006-01-05 * Merged further fixes from Russell Coker, specifically: - av_to_string overflow checking - sepol_context_to_string error handling - hierarchy checking memory leak fixes and optimizations - avrule_block_read variable initialization * Marked deprecated code in genbools and genusers. 1.11.4 2006-01-05 * Merged bugfix for sepol_port_modify from Russell Coker. 1.11.3 2006-01-05 * Fixed bug in sepol_iface_modify error path noted by Ivan Gyurdiev. * Merged port ordering patch from Ivan Gyurdiev. 1.11.2 2006-01-04 * Merged patch series from Ivan Gyurdiev. This includes patches to: - support ordering of records in compare function - enable port interfaces - add interfaces for context validity and range checks - add include guards 1.11.1 2005-12-16 * Fixed mls_range_cpy bug. 1.10 2005-12-07 * Updated version for release. 1.9.42 2005-12-05 * Dropped handle from user_del_role interface. 1.9.41 2005-11-28 * Merged remove defrole from sepol patch from Ivan Gyurdiev. 1.9.40 2005-11-15 * Merged module function and map file cleanup from Ivan Gyurdiev. * Merged MLS and genusers cleanups from Ivan Gyurdiev. 1.9.39 2005-11-09 Prepare for removal of booleans* and *.users files. * Cleaned up sepol_genbools to not regenerate the image if there were no changes in the boolean values, including the degenerate case where there are no booleans or booleans.local files. * Cleaned up sepol_genusers to not warn on missing local.users. 1.9.38 2005-11-08 * Removed sepol_port_* from libsepol.map, as the port interfaces are not yet stable. 1.9.37 2005-11-04 * Merged context destroy cleanup patch from Ivan Gyurdiev. 1.9.36 2005-11-03 * Merged context_to_string interface change patch from Ivan Gyurdiev. 1.9.35 2005-11-01 * Added src/dso.h and src/*_internal.h. Added hidden_def for exported symbols used within libsepol. Added hidden for symbols that should not be exported by the wildcards in libsepol.map. 1.9.34 2005-10-31 * Merged record interface, record bugfix, and set_roles patches from Ivan Gyurdiev. 1.9.33 2005-10-27 * Merged count specification change from Ivan Gyurdiev. 1.9.32 2005-10-26 * Added further checking and error reporting to sepol_module_package_read and _info. 1.9.31 2005-10-26 * Merged sepol handle passing, DEBUG conversion, and memory leak fix patches from Ivan Gyurdiev. 1.9.30 2005-10-25 * Removed processing of system.users from sepol_genusers and dropped delusers logic. 1.9.29 2005-10-25 * Removed policydb_destroy from error path of policydb_read, since create/init/destroy/free of policydb is handled by the caller now. * Fixed sepol_module_package_read to handle a failed policydb_read properly. 1.9.28 2005-10-25 * Merged query/exists and count patches from Ivan Gyurdiev. 1.9.27 2005-10-25 * Merged fix for pruned types in expand code from Joshua Brindle. * Merged new module package format code from Joshua Brindle. 1.9.26 2005-10-24 * Merged context interface cleanup, record conversion code, key passing, and bug fix patches from Ivan Gyurdiev. 1.9.25 2005-10-21 * Merged users cleanup patch from Ivan Gyurdiev. 1.9.24 2005-10-21 * Merged user record memory leak fix from Ivan Gyurdiev. * Merged reorganize users patch from Ivan Gyurdiev. 1.9.23 2005-10-19 * Added check flag to expand_module() to control assertion and hierarchy checking on expansion. 1.9.22 2005-10-19 * Reworked check_assertions() and hierarchy_check_constraints() to take handles and use callback-based error reporting. * Changed expand_module() to call check_assertions() and hierarchy_check_constraints() prior to returning the expanded policy. 1.9.21 2005-10-18 * Changed sepol_module_package_set_file_contexts to copy the file contexts data since it is internally managed. 1.9.20 2005-10-18 * Added sepol_policy_file_set_handle interface to associate a handle with a policy file. * Added handle argument to policydb_from_image/to_image. * Added sepol_module_package_set_file_contexts interface. * Dropped sepol_module_package_create_file interface. * Reworked policydb_read/write, policydb_from_image/to_image, and sepol_module_package_read/write to use callback-based error reporting system rather than DEBUG. 1.9.19 2005-10-17 * Reworked link_packages, link_modules, and expand_module to use callback-based error reporting system rather than error buffering. 1.9.18 2005-10-14 * Merged conditional expression mapping fix in the module linking code from Joshua Brindle. 1.9.17 2005-10-13 * Hid sepol_module_package type definition, and added get interfaces. 1.9.16 2005-10-13 * Merged new callback-based error reporting system from Ivan Gyurdiev. 1.9.15 2005-10-13 * Merged support for require blocks inside conditionals from Joshua Brindle (Tresys). 1.9.14 2005-10-07 * Fixed use of policydb_from_image/to_image to ensure proper init of policydb. 1.9.13 2005-10-07 * Isolated policydb internal headers under . These headers should only be used by users of the static libsepol. Created new with new public types and interfaces for shared libsepol. Created new with public types and interfaces moved or wrapped from old module.h, link.h, and expand.h, adjusted for new public types for policydb and policy_file. Added public interfaces to libsepol.map. Some implementation changes visible to users of the static libsepol: 1) policydb_read no longer calls policydb_init. Caller must do so first. 2) policydb_init no longer takes policy_type argument. Caller must set policy_type separately. 3) expand_module automatically enables the global branch. Caller no longer needs to do so. 4) policydb_write uses the policy_type and policyvers from the policydb itself, and sepol_set_policyvers() has been removed. 1.9.12 2005-10-06 * Merged function renaming and static cleanup from Ivan Gyurdiev. 1.9.11 2005-10-05 * Merged bug fix for check_assertions handling of no assertions from Joshua Brindle (Tresys). 1.9.10 2005-10-04 * Merged iterate patch from Ivan Gyurdiev. 1.9.9 2005-10-03 * Merged MLS in modules patch from Joshua Brindle (Tresys). 1.9.8 2005-09-30 * Merged pointer typedef elimination patch from Ivan Gyurdiev. * Merged user list function, new mls functions, and bugfix patch from Ivan Gyurdiev. 1.9.7 2005-09-28 * Merged sepol_get_num_roles fix from Karl MacMillan (Tresys). 1.9.6 2005-09-23 * Merged bug fix patches from Joshua Brindle (Tresys). 1.9.5 2005-09-21 * Merged boolean record and memory leak fix patches from Ivan Gyurdiev. 1.9.4 2005-09-19 * Merged interface record patch from Ivan Gyurdiev. 1.9.3 2005-09-14 * Merged fix for sepol_enable/disable_debug from Ivan Gyurdiev. 1.9.2 2005-09-14 * Merged stddef.h patch and debug conversion patch from Ivan Gyurdiev. 1.9.1 2005-09-09 * Fixed expand_avtab and expand_cond_av_list to keep separate entries with identical keys but different enabled flags. 1.8 2005-09-06 * Updated version for release. 1.7.24 2005-08-31 * Fixed symtab_insert return value for duplicate declarations. 1.7.23 2005-08-31 * Merged fix for memory error in policy_module_destroy from Jason Tang (Tresys). 1.7.22 2005-08-26 * Merged fix for memory leak in sepol_context_to_sid from Jason Tang (Tresys). 1.7.21 2005-08-25 * Merged fixes for resource leaks on error paths and change to scope_destroy from Joshua Brindle (Tresys). 1.7.20 2005-08-23 * Merged more fixes for resource leaks on error paths from Serge Hallyn (IBM). Bugs found by Coverity. 1.7.19 2005-08-19 * Changed to treat all type conflicts as fatal errors. 1.7.18 2005-08-18 * Merged several error handling fixes from Serge Hallyn (IBM). Bugs found by Coverity. 1.7.17 2005-08-15 * Fixed further memory leaks found by valgrind. 1.7.16 2005-08-15 * Fixed several memory leaks found by valgrind. 1.7.15 2005-08-12 * Fixed empty list test in cond_write_av_list. Bug found by Coverity, reported by Serge Hallyn (IBM). * Merged patch to policydb_write to check errors when writing the type->attribute reverse map from Serge Hallyn (IBM). Bug found by Coverity. * Fixed policydb_destroy to properly handle NULL type_attr_map or attr_type_map. 1.7.14 2005-08-12 * Fixed use of uninitialized data by expand_avtab_node by clearing type_val_to_struct in policydb_index_others. 1.7.13 2005-08-11 * Improved memory use by SELinux by both reducing the avtab node size and reducing the number of avtab nodes (by not expanding attributes in TE rules when possible). Added expand_avtab and expand_cond_av_list functions for use by assertion checker, hierarchy checker, compatibility code, and dispol. Added new inline ebitmap operators and converted existing users of ebitmaps to the new operators for greater efficiency. Note: The binary policy format version has been incremented to version 20 as a result of these changes. 1.7.12 2005-08-10 * Fixed bug in constraint_node_clone handling of name sets. 1.7.11 2005-08-08 * Fix range_trans_clone to map the type values properly. 1.7.10 2005-08-02 * Merged patch to move module read/write code from libsemanage to libsepol from Jason Tang (Tresys). 1.7.9 2005-08-02 * Enabled further compiler warning flags and fixed them. 1.7.8 2005-08-02 * Merged user, context, port records patch from Ivan Gyurdiev. * Merged key extract function patch from Ivan Gyurdiev. 1.7.7 2005-07-27 * Merged mls_context_to_sid bugfix from Ivan Gyurdiev. 1.7.6 2005-07-26 * Merged context reorganization, memory leak fixes, port and interface loading, replacements for genusers and genbools, debug traceback, and bugfix patches from Ivan Gyurdiev. * Merged uninitialized variable bugfix from Dan Walsh. 1.7.5 2005-07-18 * Merged debug support, policydb conversion functions from Ivan Gyurdiev (Red Hat). * Removed genpolbools and genpolusers utilities. 1.7.4 2005-07-18 * Merged hierarchy check fix from Joshua Brindle (Tresys). 1.7.3 2005-07-13 * Merged header file cleanup and memory leak fix from Ivan Gyurdiev (Red Hat). 1.7.2 2005-07-11 * Merged genbools debugging message cleanup from Red Hat. 1.7.1 2005-07-06 * Merged loadable module support from Tresys Technology. 1.6 2005-06-20 * Updated version for release. 1.5.10 2005-05-19 * License changed to LGPL v2.1, see COPYING. 1.5.9 2005-05-16 * Added sepol_genbools_policydb and sepol_genusers_policydb for audit2why. 1.5.8 2005-05-13 * Added sepol_ prefix to Flask types to avoid namespace collision with libselinux. 1.5.7 2005-05-13 * Added sepol_compute_av_reason() for audit2why. 1.5.6 2005-04-25 * Fixed bug in role hierarchy checker. 1.5.5 2005-04-13 * Merged hierarchical type/role patch from Tresys Technology. * Merged MLS fixes from Darrel Goeddel of TCS. 1.5.4 2005-04-13 * Changed sepol_genusers to not delete users by default, and added a sepol_set_delusers function to enable deletion. Also, removed special case handling of system_u and user_u. 1.5.3 2005-03-29 * Merged booleans.local patch from Dan Walsh. 1.5.2 2005-03-16 * Added man page for sepol_check_context. 1.5.1 2005-03-15 * Added man page for sepol_genusers function. * Merged man pages for genpolusers and chkcon from Manoj Srivastava. 1.4 2005-03-09 * Updated version for release. 1.3.8 2005-03-08 * Cleaned up error handling in sepol_genusers and sepol_genbools. 1.3.7 2005-02-28 * Merged sepol_debug and fclose patch from Dan Walsh. 1.3.6 2005-02-22 * Changed sepol_genusers to also use getline and correctly handle EOL. 1.3.5 2005-02-17 * Merged range_transition support from Darrel Goeddel (TCS). 1.3.4 2005-02-16 * Added sepol_genusers function. 1.3.3 2005-02-14 * Merged endianness and compute_av patches from Darrel Goeddel (TCS). 1.3.2 2005-02-09 * Changed relabel Makefile target to use restorecon. 1.3.1 2005-01-26 * Merged enhanced MLS support from Darrel Goeddel (TCS). 1.2.1 2005-01-19 * Merged build fix patch from Manoj Srivastava. 1.2 2004-10-07 * MLS build fixes. * Added sepol_set_policydb_from_file and sepol_check_context for setfiles. 1.0 2004-08-19 * Initial public release. 0.4 2004-08-13 * Merged patch from Dan Walsh to ignore case on booleans. * Changed sepol_genbools* to preserve the original policy version. * Replaced exported global variables with set functions. * Moved genpolbools utility from checkpolicy to libsepol. * Added man pages for sepol_genbools* and genpolbools. 0.3 2004-08-10 * Added ChangeLog, COPYING, spec file. * Added sepol_genbools_array() for load_policy. * Created libsepol.map to limit exported symbols in shared library. 0.2 2004-08-09 * Exported other functions for checkpolicy and friends. * Renamed service and sidtab functions to avoid libselinux conflict. * Removed original code from checkpolicy, which now uses libsepol. * Code cleanup: kill legacy references to kernel types/functions. 0.1 2004-08-06 * Moved checkpolicy core logic into a library. * Exported sepol_genbools() for load_policy. libsepol-2.2/Makefile000066400000000000000000000005611223423440700146310ustar00rootroot00000000000000all: $(MAKE) -C src $(MAKE) -C utils install: $(MAKE) -C include install $(MAKE) -C src install $(MAKE) -C utils install $(MAKE) -C man install relabel: $(MAKE) -C src relabel clean: $(MAKE) -C src clean $(MAKE) -C utils clean $(MAKE) -C tests clean indent: $(MAKE) -C src $@ $(MAKE) -C include $@ $(MAKE) -C utils $@ test: $(MAKE) -C tests test libsepol-2.2/VERSION000066400000000000000000000000041223423440700142310ustar00rootroot000000000000002.2 libsepol-2.2/include/000077500000000000000000000000001223423440700146125ustar00rootroot00000000000000libsepol-2.2/include/Makefile000066400000000000000000000006111223423440700162500ustar00rootroot00000000000000# Installation directories. PREFIX ?= $(DESTDIR)/usr INCDIR ?= $(PREFIX)/include/sepol all: install: all test -d $(INCDIR) || install -m 755 -d $(INCDIR) test -d $(INCDIR)/policydb || install -m 755 -d $(INCDIR)/policydb install -m 644 $(wildcard sepol/*.h) $(INCDIR) install -m 644 $(wildcard sepol/policydb/*.h) $(INCDIR)/policydb indent: ../../scripts/Lindent $(wildcard sepol/*.h) libsepol-2.2/include/sepol/000077500000000000000000000000001223423440700157345ustar00rootroot00000000000000libsepol-2.2/include/sepol/boolean_record.h000066400000000000000000000027121223423440700210640ustar00rootroot00000000000000#ifndef _SEPOL_BOOLEAN_RECORD_H_ #define _SEPOL_BOOLEAN_RECORD_H_ #include #include struct sepol_bool; struct sepol_bool_key; typedef struct sepol_bool sepol_bool_t; typedef struct sepol_bool_key sepol_bool_key_t; /* Key */ extern int sepol_bool_key_create(sepol_handle_t * handle, const char *name, sepol_bool_key_t ** key); extern void sepol_bool_key_unpack(const sepol_bool_key_t * key, const char **name); extern int sepol_bool_key_extract(sepol_handle_t * handle, const sepol_bool_t * boolean, sepol_bool_key_t ** key_ptr); extern void sepol_bool_key_free(sepol_bool_key_t * key); extern int sepol_bool_compare(const sepol_bool_t * boolean, const sepol_bool_key_t * key); extern int sepol_bool_compare2(const sepol_bool_t * boolean, const sepol_bool_t * boolean2); /* Name */ extern const char *sepol_bool_get_name(const sepol_bool_t * boolean); extern int sepol_bool_set_name(sepol_handle_t * handle, sepol_bool_t * boolean, const char *name); /* Value */ extern int sepol_bool_get_value(const sepol_bool_t * boolean); extern void sepol_bool_set_value(sepol_bool_t * boolean, int value); /* Create/Clone/Destroy */ extern int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr); extern int sepol_bool_clone(sepol_handle_t * handle, const sepol_bool_t * boolean, sepol_bool_t ** bool_ptr); extern void sepol_bool_free(sepol_bool_t * boolean); #endif libsepol-2.2/include/sepol/booleans.h000066400000000000000000000041711223423440700177120ustar00rootroot00000000000000#ifndef _SEPOL_BOOLEANS_H_ #define _SEPOL_BOOLEANS_H_ #include #include #include #include /*--------------compatibility--------------*/ /* Given an existing binary policy (starting at 'data', with length 'len') and a boolean configuration file named by 'boolpath', rewrite the binary policy for the boolean settings in the boolean configuration file. The binary policy is rewritten in place in memory. Returns 0 upon success, or -1 otherwise. */ extern int sepol_genbools(void *data, size_t len, char *boolpath); /* Given an existing binary policy (starting at 'data', with length 'len') and boolean settings specified by the parallel arrays ('names', 'values') with 'nel' elements, rewrite the binary policy for the boolean settings. The binary policy is rewritten in place in memory. Returns 0 upon success or -1 otherwise. */ extern int sepol_genbools_array(void *data, size_t len, char **names, int *values, int nel); /*---------------end compatbility------------*/ /* Set the specified boolean */ extern int sepol_bool_set(sepol_handle_t * handle, sepol_policydb_t * policydb, const sepol_bool_key_t * key, const sepol_bool_t * data); /* Return the number of booleans */ extern int sepol_bool_count(sepol_handle_t * handle, const sepol_policydb_t * p, unsigned int *response); /* Check if the specified boolean exists */ extern int sepol_bool_exists(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_bool_key_t * key, int *response); /* Query a boolean - returns the boolean, or NULL if not found */ extern int sepol_bool_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_bool_key_t * key, sepol_bool_t ** response); /* Iterate the booleans * The handler may return: * -1 to signal an error condition, * 1 to signal successful exit * 0 to signal continue */ extern int sepol_bool_iterate(sepol_handle_t * handle, const sepol_policydb_t * policydb, int (*fn) (const sepol_bool_t * boolean, void *fn_arg), void *arg); #endif libsepol-2.2/include/sepol/context.h000066400000000000000000000012521223423440700175710ustar00rootroot00000000000000#ifndef _SEPOL_CONTEXT_H_ #define _SEPOL_CONTEXT_H_ #include #include #include /* -- Deprecated -- */ extern int sepol_check_context(const char *context); /* -- End deprecated -- */ extern int sepol_context_check(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_context_t * context); extern int sepol_mls_contains(sepol_handle_t * handle, const sepol_policydb_t * policydb, const char *mls1, const char *mls2, int *response); extern int sepol_mls_check(sepol_handle_t * handle, const sepol_policydb_t * policydb, const char *mls); #endif libsepol-2.2/include/sepol/context_record.h000066400000000000000000000031011223423440700211220ustar00rootroot00000000000000#ifndef _SEPOL_CONTEXT_RECORD_H_ #define _SEPOL_CONTEXT_RECORD_H_ #include struct sepol_context; typedef struct sepol_context sepol_context_t; /* We don't need a key, because the context is never stored * in a data collection by itself */ /* User */ extern const char *sepol_context_get_user(const sepol_context_t * con); extern int sepol_context_set_user(sepol_handle_t * handle, sepol_context_t * con, const char *user); /* Role */ extern const char *sepol_context_get_role(const sepol_context_t * con); extern int sepol_context_set_role(sepol_handle_t * handle, sepol_context_t * con, const char *role); /* Type */ extern const char *sepol_context_get_type(const sepol_context_t * con); extern int sepol_context_set_type(sepol_handle_t * handle, sepol_context_t * con, const char *type); /* MLS */ extern const char *sepol_context_get_mls(const sepol_context_t * con); extern int sepol_context_set_mls(sepol_handle_t * handle, sepol_context_t * con, const char *mls_range); /* Create/Clone/Destroy */ extern int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr); extern int sepol_context_clone(sepol_handle_t * handle, const sepol_context_t * con, sepol_context_t ** con_ptr); extern void sepol_context_free(sepol_context_t * con); /* Parse to/from string */ extern int sepol_context_from_string(sepol_handle_t * handle, const char *str, sepol_context_t ** con); extern int sepol_context_to_string(sepol_handle_t * handle, const sepol_context_t * con, char **str_ptr); #endif libsepol-2.2/include/sepol/debug.h000066400000000000000000000016111223423440700171720ustar00rootroot00000000000000#ifndef _SEPOL_DEBUG_H_ #define _SEPOL_DEBUG_H_ #include /* Deprecated */ extern void sepol_debug(int on); /* End deprecated */ #define SEPOL_MSG_ERR 1 #define SEPOL_MSG_WARN 2 #define SEPOL_MSG_INFO 3 extern int sepol_msg_get_level(sepol_handle_t * handle); extern const char *sepol_msg_get_channel(sepol_handle_t * handle); extern const char *sepol_msg_get_fname(sepol_handle_t * handle); /* Set the messaging callback. * By the default, the callback will print * the message on standard output, in a * particular format. Passing NULL here * indicates that messaging should be suppressed */ extern void sepol_msg_set_callback(sepol_handle_t * handle, #ifdef __GNUC__ __attribute__ ((format(printf, 3, 4))) #endif void (*msg_callback) (void *varg, sepol_handle_t * handle, const char *fmt, ...), void *msg_callback_arg); #endif libsepol-2.2/include/sepol/errcodes.h000066400000000000000000000014171223423440700177160ustar00rootroot00000000000000/* Author: Karl MacMillan */ #ifndef __sepol_errno_h__ #define __sepol_errno_h__ #include #define SEPOL_OK 0 /* These first error codes are defined for compatibility with * previous version of libsepol. In the future, custome error * codes that don't map to system error codes should be defined * outside of the range of system error codes. */ #define SEPOL_ERR -1 #define SEPOL_ENOTSUP -2 /* feature not supported in module language */ #define SEPOL_EREQ -3 /* requirements not met */ /* Error codes that map to system error codes */ #define SEPOL_ENOMEM -ENOMEM #define SEPOL_ERANGE -ERANGE #define SEPOL_EEXIST -EEXIST #define SEPOL_ENOENT -ENOENT #endif libsepol-2.2/include/sepol/handle.h000066400000000000000000000024541223423440700173450ustar00rootroot00000000000000#ifndef _SEPOL_HANDLE_H_ #define _SEPOL_HANDLE_H_ struct sepol_handle; typedef struct sepol_handle sepol_handle_t; /* Create and return a sepol handle. */ sepol_handle_t *sepol_handle_create(void); /* Get whether or not dontaudits will be disabled, same values as * specified by set_disable_dontaudit. This value reflects the state * your system will be set to upon commit, not necessarily its * current state.*/ int sepol_get_disable_dontaudit(sepol_handle_t * sh); /* Set whether or not to disable dontaudits, 0 is default and does * not disable dontaudits, 1 disables them */ void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit); /* Set whether module_expand() should consume the base policy passed in. * This should reduce the amount of memory required to expand the policy. */ void sepol_set_expand_consume_base(sepol_handle_t * sh, int consume_base); /* Destroy a sepol handle. */ void sepol_handle_destroy(sepol_handle_t *); /* Get whether or not needless unused branch of tunables would be preserved */ int sepol_get_preserve_tunables(sepol_handle_t * sh); /* Set whether or not to preserve the needless unused branch of tunables, * 0 is default and discard such branch, 1 preserves them */ void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables); #endif libsepol-2.2/include/sepol/iface_record.h000066400000000000000000000033531223423440700205160ustar00rootroot00000000000000#ifndef _SEPOL_IFACE_RECORD_H_ #define _SEPOL_IFACE_RECORD_H_ #include #include struct sepol_iface; struct sepol_iface_key; typedef struct sepol_iface sepol_iface_t; typedef struct sepol_iface_key sepol_iface_key_t; /* Key */ extern int sepol_iface_compare(const sepol_iface_t * iface, const sepol_iface_key_t * key); extern int sepol_iface_compare2(const sepol_iface_t * iface, const sepol_iface_t * iface2); extern void sepol_iface_key_unpack(const sepol_iface_key_t * key, const char **name); extern int sepol_iface_key_create(sepol_handle_t * handle, const char *name, sepol_iface_key_t ** key_ptr); extern int sepol_iface_key_extract(sepol_handle_t * handle, const sepol_iface_t * iface, sepol_iface_key_t ** key_ptr); extern void sepol_iface_key_free(sepol_iface_key_t * key); /* Name */ extern const char *sepol_iface_get_name(const sepol_iface_t * iface); extern int sepol_iface_set_name(sepol_handle_t * handle, sepol_iface_t * iface, const char *name); /* Context */ extern sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface); extern int sepol_iface_set_ifcon(sepol_handle_t * handle, sepol_iface_t * iface, sepol_context_t * con); extern sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface); extern int sepol_iface_set_msgcon(sepol_handle_t * handle, sepol_iface_t * iface, sepol_context_t * con); /* Create/Clone/Destroy */ extern int sepol_iface_create(sepol_handle_t * handle, sepol_iface_t ** iface_ptr); extern int sepol_iface_clone(sepol_handle_t * handle, const sepol_iface_t * iface, sepol_iface_t ** iface_ptr); extern void sepol_iface_free(sepol_iface_t * iface); #endif libsepol-2.2/include/sepol/interfaces.h000066400000000000000000000024661223423440700202400ustar00rootroot00000000000000#ifndef __SEPOL_INTERFACES_H_ #define __SEPOL_INTERFACES_H_ #include #include #include /* Return the number of interfaces */ extern int sepol_iface_count(sepol_handle_t * handle, const sepol_policydb_t * policydb, unsigned int *response); /* Check if an interface exists */ extern int sepol_iface_exists(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_iface_key_t * key, int *response); /* Query an interface - returns the interface, * or NULL if not found */ extern int sepol_iface_query(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_iface_key_t * key, sepol_iface_t ** response); /* Modify an interface, or add it, if the key * is not found */ extern int sepol_iface_modify(sepol_handle_t * handle, sepol_policydb_t * policydb, const sepol_iface_key_t * key, const sepol_iface_t * data); /* Iterate the interfaces * The handler may return: * -1 to signal an error condition, * 1 to signal successful exit * 0 to signal continue */ extern int sepol_iface_iterate(sepol_handle_t * handle, const sepol_policydb_t * policydb, int (*fn) (const sepol_iface_t * iface, void *fn_arg), void *arg); #endif libsepol-2.2/include/sepol/module.h000066400000000000000000000050631223423440700173760ustar00rootroot00000000000000#ifndef _SEPOL_MODULE_H_ #define _SEPOL_MODULE_H_ #include #include #include #include #include struct sepol_module_package; typedef struct sepol_module_package sepol_module_package_t; /* Module package public interfaces. */ extern int sepol_module_package_create(sepol_module_package_t ** p); extern void sepol_module_package_free(sepol_module_package_t * p); extern char *sepol_module_package_get_file_contexts(sepol_module_package_t * p); extern size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p); extern int sepol_module_package_set_file_contexts(sepol_module_package_t * p, char *data, size_t len); extern char *sepol_module_package_get_seusers(sepol_module_package_t * p); extern size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p); extern int sepol_module_package_set_seusers(sepol_module_package_t * p, char *data, size_t len); extern char *sepol_module_package_get_user_extra(sepol_module_package_t * p); extern size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p); extern int sepol_module_package_set_user_extra(sepol_module_package_t * p, char *data, size_t len); extern char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p); extern size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p); extern int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p, char *data, size_t len); extern sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p); extern int sepol_link_packages(sepol_handle_t * handle, sepol_module_package_t * base, sepol_module_package_t ** modules, int num_modules, int verbose); extern int sepol_module_package_read(sepol_module_package_t * mod, struct sepol_policy_file *file, int verbose); extern int sepol_module_package_info(struct sepol_policy_file *file, int *type, char **name, char **version); extern int sepol_module_package_write(sepol_module_package_t * p, struct sepol_policy_file *file); /* Module linking/expanding public interfaces. */ extern int sepol_link_modules(sepol_handle_t * handle, sepol_policydb_t * base, sepol_policydb_t ** modules, size_t len, int verbose); extern int sepol_expand_module(sepol_handle_t * handle, sepol_policydb_t * base, sepol_policydb_t * out, int verbose, int check); #endif libsepol-2.2/include/sepol/node_record.h000066400000000000000000000052611223423440700203740ustar00rootroot00000000000000#ifndef _SEPOL_NODE_RECORD_H_ #define _SEPOL_NODE_RECORD_H_ #include #include #include struct sepol_node; struct sepol_node_key; typedef struct sepol_node sepol_node_t; typedef struct sepol_node_key sepol_node_key_t; #define SEPOL_PROTO_IP4 0 #define SEPOL_PROTO_IP6 1 /* Key */ extern int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key); extern int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2); extern int sepol_node_key_create(sepol_handle_t * handle, const char *addr, const char *mask, int proto, sepol_node_key_t ** key_ptr); extern void sepol_node_key_unpack(const sepol_node_key_t * key, const char **addr, const char **mask, int *proto); extern int sepol_node_key_extract(sepol_handle_t * handle, const sepol_node_t * node, sepol_node_key_t ** key_ptr); extern void sepol_node_key_free(sepol_node_key_t * key); /* Address */ extern int sepol_node_get_addr(sepol_handle_t * handle, const sepol_node_t * node, char **addr); extern int sepol_node_get_addr_bytes(sepol_handle_t * handle, const sepol_node_t * node, char **addr, size_t * addr_sz); extern int sepol_node_set_addr(sepol_handle_t * handle, sepol_node_t * node, int proto, const char *addr); extern int sepol_node_set_addr_bytes(sepol_handle_t * handle, sepol_node_t * node, const char *addr, size_t addr_sz); /* Netmask */ extern int sepol_node_get_mask(sepol_handle_t * handle, const sepol_node_t * node, char **mask); extern int sepol_node_get_mask_bytes(sepol_handle_t * handle, const sepol_node_t * node, char **mask, size_t * mask_sz); extern int sepol_node_set_mask(sepol_handle_t * handle, sepol_node_t * node, int proto, const char *mask); extern int sepol_node_set_mask_bytes(sepol_handle_t * handle, sepol_node_t * node, const char *mask, size_t mask_sz); /* Protocol */ extern int sepol_node_get_proto(const sepol_node_t * node); extern void sepol_node_set_proto(sepol_node_t * node, int proto); extern const char *sepol_node_get_proto_str(int proto); /* Context */ extern sepol_context_t *sepol_node_get_con(const sepol_node_t * node); extern int sepol_node_set_con(sepol_handle_t * handle, sepol_node_t * node, sepol_context_t * con); /* Create/Clone/Destroy */ extern int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node_ptr); extern int sepol_node_clone(sepol_handle_t * handle, const sepol_node_t * node, sepol_node_t ** node_ptr); extern void sepol_node_free(sepol_node_t * node); #endif libsepol-2.2/include/sepol/nodes.h000066400000000000000000000023331223423440700172160ustar00rootroot00000000000000#ifndef _SEPOL_NODES_H_ #define _SEPOL_NODES_H_ #include #include #include /* Return the number of nodes */ extern int sepol_node_count(sepol_handle_t * handle, const sepol_policydb_t * p, unsigned int *response); /* Check if a node exists */ extern int sepol_node_exists(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_node_key_t * key, int *response); /* Query a node - returns the node, or NULL if not found */ extern int sepol_node_query(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_node_key_t * key, sepol_node_t ** response); /* Modify a node, or add it, if the key is not found */ extern int sepol_node_modify(sepol_handle_t * handle, sepol_policydb_t * policydb, const sepol_node_key_t * key, const sepol_node_t * data); /* Iterate the nodes * The handler may return: * -1 to signal an error condition, * 1 to signal successful exit * 0 to signal continue */ extern int sepol_node_iterate(sepol_handle_t * handle, const sepol_policydb_t * policydb, int (*fn) (const sepol_node_t * node, void *fn_arg), void *arg); #endif libsepol-2.2/include/sepol/policydb.h000066400000000000000000000105211223423440700177110ustar00rootroot00000000000000#ifndef _SEPOL_POLICYDB_H_ #define _SEPOL_POLICYDB_H_ #include #include #include struct sepol_policy_file; typedef struct sepol_policy_file sepol_policy_file_t; struct sepol_policydb; typedef struct sepol_policydb sepol_policydb_t; /* Policy file public interfaces. */ /* Create and free memory associated with a policy file. */ extern int sepol_policy_file_create(sepol_policy_file_t ** pf); extern void sepol_policy_file_free(sepol_policy_file_t * pf); /* * Set the policy file to represent a binary policy memory image. * Subsequent operations using the policy file will read and write * the image located at the specified address with the specified length. * If 'len' is 0, then merely compute the necessary length upon * subsequent policydb write operations in order to determine the * necessary buffer size to allocate. */ extern void sepol_policy_file_set_mem(sepol_policy_file_t * pf, char *data, size_t len); /* * Get the size of the buffer needed to store a policydb write * previously done on this policy file. */ extern int sepol_policy_file_get_len(sepol_policy_file_t * pf, size_t * len); /* * Set the policy file to represent a FILE. * Subsequent operations using the policy file will read and write * to the FILE. */ extern void sepol_policy_file_set_fp(sepol_policy_file_t * pf, FILE * fp); /* * Associate a handle with a policy file, for use in * error reporting from subsequent calls that take the * policy file as an argument. */ extern void sepol_policy_file_set_handle(sepol_policy_file_t * pf, sepol_handle_t * handle); /* Policydb public interfaces. */ /* Create and free memory associated with a policydb. */ extern int sepol_policydb_create(sepol_policydb_t ** p); extern void sepol_policydb_free(sepol_policydb_t * p); /* Legal types of policies that the policydb can represent. */ #define SEPOL_POLICY_KERN 0 #define SEPOL_POLICY_BASE 1 #define SEPOL_POLICY_MOD 2 /* * Range of policy versions for the kernel policy type supported * by this library. */ extern int sepol_policy_kern_vers_min(void); extern int sepol_policy_kern_vers_max(void); /* * Set the policy type as specified, and automatically initialize the * policy version accordingly to the maximum version supported for the * policy type. * Returns -1 if the policy type is not legal. */ extern int sepol_policydb_set_typevers(sepol_policydb_t * p, unsigned int type); /* * Set the policy version to a different value. * Returns -1 if the policy version is not in the supported range for * the (previously set) policy type. */ extern int sepol_policydb_set_vers(sepol_policydb_t * p, unsigned int vers); /* Set how to handle unknown class/perms. */ #define SEPOL_DENY_UNKNOWN 0 #define SEPOL_REJECT_UNKNOWN 2 #define SEPOL_ALLOW_UNKNOWN 4 extern int sepol_policydb_set_handle_unknown(sepol_policydb_t * p, unsigned int handle_unknown); /* * Read a policydb from a policy file. * This automatically sets the type and version based on the * image contents. */ extern int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf); /* * Write a policydb to a policy file. * The generated image will be in the binary format corresponding * to the policy version associated with the policydb. */ extern int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf); /* * Extract a policydb from a binary policy memory image. * This is equivalent to sepol_policydb_read with a policy file * set to refer to memory. */ extern int sepol_policydb_from_image(sepol_handle_t * handle, void *data, size_t len, sepol_policydb_t * p); /* * Generate a binary policy memory image from a policydb. * This is equivalent to sepol_policydb_write with a policy file * set to refer to memory, but internally handles computing the * necessary length and allocating an appropriately sized memory * buffer for the caller. */ extern int sepol_policydb_to_image(sepol_handle_t * handle, sepol_policydb_t * p, void **newdata, size_t * newlen); /* * Check whether the policydb has MLS enabled. */ extern int sepol_policydb_mls_enabled(const sepol_policydb_t * p); /* * Check whether the compatibility mode for SELinux network * checks should be enabled when using this policy. */ extern int sepol_policydb_compat_net(const sepol_policydb_t * p); #endif libsepol-2.2/include/sepol/policydb/000077500000000000000000000000001223423440700175415ustar00rootroot00000000000000libsepol-2.2/include/sepol/policydb/avrule_block.h000066400000000000000000000030401223423440700223570ustar00rootroot00000000000000/* Authors: Jason Tang * * Copyright (C) 2005 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 */ #ifndef _SEPOL_AVRULE_BLOCK_H_ #define _SEPOL_AVRULE_BLOCK_H_ #include extern avrule_block_t *avrule_block_create(void); extern void avrule_block_destroy(avrule_block_t * x); extern avrule_decl_t *avrule_decl_create(uint32_t decl_id); extern void avrule_decl_destroy(avrule_decl_t * x); extern void avrule_block_list_destroy(avrule_block_t * x); extern avrule_decl_t *get_avrule_decl(policydb_t * p, uint32_t decl_id); extern cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl, cond_list_t * cond); extern int is_id_enabled(char *id, policydb_t * p, int symbol_table); extern int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p); #endif libsepol-2.2/include/sepol/policydb/avtab.h000066400000000000000000000077241223423440700210210ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Yuichi Nakamura * Tuned number of hash slots for avtab to reduce memory usage */ /* Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * * Copyright (C) 2003 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 */ /* FLASK */ /* * An access vector table (avtab) is a hash table * of access vectors and transition types indexed * by a type pair and a class. An access vector * table is used to represent the type enforcement * tables. */ #ifndef _SEPOL_POLICYDB_AVTAB_H_ #define _SEPOL_POLICYDB_AVTAB_H_ #include #include typedef struct avtab_key { uint16_t source_type; uint16_t target_type; uint16_t target_class; #define AVTAB_ALLOWED 1 #define AVTAB_AUDITALLOW 2 #define AVTAB_AUDITDENY 4 #define AVTAB_NEVERALLOW 128 #define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) #define AVTAB_TRANSITION 16 #define AVTAB_MEMBER 32 #define AVTAB_CHANGE 64 #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) #define AVTAB_ENABLED_OLD 0x80000000 #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ uint16_t specified; /* what fields are specified */ } avtab_key_t; typedef struct avtab_datum { uint32_t data; /* access vector or type */ } avtab_datum_t; typedef struct avtab_node *avtab_ptr_t; struct avtab_node { avtab_key_t key; avtab_datum_t datum; avtab_ptr_t next; void *parse_context; /* generic context pointer used by parser; * not saved in binary policy */ unsigned merged; /* flag for avtab_write only; not saved in binary policy */ }; typedef struct avtab { avtab_ptr_t *htable; uint32_t nel; /* number of elements */ uint32_t nslot; /* number of hash slots */ uint16_t mask; /* mask to compute hash func */ } avtab_t; extern int avtab_init(avtab_t *); extern int avtab_alloc(avtab_t *, uint32_t); extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d); extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k); extern void avtab_destroy(avtab_t * h); extern int avtab_map(avtab_t * h, int (*apply) (avtab_key_t * k, avtab_datum_t * d, void *args), void *args); extern void avtab_hash_eval(avtab_t * h, char *tag); struct policy_file; extern int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, int (*insert) (avtab_t * a, avtab_key_t * k, avtab_datum_t * d, void *p), void *p); extern int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers); extern avtab_ptr_t avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum); extern avtab_ptr_t avtab_insert_with_parse_context(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum, void *parse_context); extern avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key); extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified); #define MAX_AVTAB_HASH_BITS 13 #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) #define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS #endif /* _AVTAB_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/conditional.h000066400000000000000000000110701223423440700222140ustar00rootroot00000000000000/* Authors: Karl MacMillan * Frank Mayer * * Copyright (C) 2003 - 2005 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 */ #ifndef _SEPOL_POLICYDB_CONDITIONAL_H_ #define _SEPOL_POLICYDB_CONDITIONAL_H_ #include #include #include #include #define COND_EXPR_MAXDEPTH 10 /* this is the max unique bools in a conditional expression * for which we precompute all outcomes for the expression. * * NOTE - do _NOT_ use value greater than 5 because * cond_node_t->expr_pre_comp can only hold at most 32 values */ #define COND_MAX_BOOLS 5 /* * A conditional expression is a list of operators and operands * in reverse polish notation. */ typedef struct cond_expr { #define COND_BOOL 1 /* plain bool */ #define COND_NOT 2 /* !bool */ #define COND_OR 3 /* bool || bool */ #define COND_AND 4 /* bool && bool */ #define COND_XOR 5 /* bool ^ bool */ #define COND_EQ 6 /* bool == bool */ #define COND_NEQ 7 /* bool != bool */ #define COND_LAST COND_NEQ uint32_t expr_type; uint32_t bool; struct cond_expr *next; } cond_expr_t; /* * Each cond_node_t contains a list of rules to be enabled/disabled * depending on the current value of the conditional expression. This * struct is for that list. */ typedef struct cond_av_list { avtab_ptr_t node; struct cond_av_list *next; } cond_av_list_t; /* * A cond node represents a conditional block in a policy. It * contains a conditional expression, the current state of the expression, * two lists of rules to enable/disable depending on the value of the * expression (the true list corresponds to if and the false list corresponds * to else).. */ typedef struct cond_node { int cur_state; cond_expr_t *expr; /* these true/false lists point into te_avtab when that is used */ cond_av_list_t *true_list; cond_av_list_t *false_list; /* and these are used during parsing and for modules */ avrule_t *avtrue_list; avrule_t *avfalse_list; /* these fields are not written to binary policy */ unsigned int nbools; uint32_t bool_ids[COND_MAX_BOOLS]; uint32_t expr_pre_comp; struct cond_node *next; /* a tunable conditional, calculated and used at expansion */ #define COND_NODE_FLAGS_TUNABLE 0x01 uint32_t flags; } cond_node_t; extern int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr); extern cond_expr_t *cond_copy_expr(cond_expr_t * expr); extern int cond_expr_equal(cond_node_t * a, cond_node_t * b); extern int cond_normalize_expr(policydb_t * p, cond_node_t * cn); extern void cond_node_destroy(cond_node_t * node); extern void cond_expr_destroy(cond_expr_t * expr); extern cond_node_t *cond_node_find(policydb_t * p, cond_node_t * needle, cond_node_t * haystack, int *was_created); extern cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node); extern cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list, cond_node_t * cn); extern int evaluate_conds(policydb_t * p); extern avtab_datum_t *cond_av_list_search(avtab_key_t * key, cond_av_list_t * cond_list); extern void cond_av_list_destroy(cond_av_list_t * list); extern void cond_optimize_lists(cond_list_t * cl); extern int cond_policydb_init(policydb_t * p); extern void cond_policydb_destroy(policydb_t * p); extern void cond_list_destroy(cond_list_t * list); extern int cond_init_bool_indexes(policydb_t * p); extern int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p); extern int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap); extern int cond_read_bool(policydb_t * p, hashtab_t h, struct policy_file *fp); extern int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp); extern void cond_compute_av(avtab_t * ctab, avtab_key_t * key, struct sepol_av_decision *avd); #endif /* _CONDITIONAL_H_ */ libsepol-2.2/include/sepol/policydb/constraint.h000066400000000000000000000047101223423440700221000ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A constraint is a condition that must be satisfied in * order for one or more permissions to be granted. * Constraints are used to impose additional restrictions * beyond the type-based rules in `te' or the role-based * transition rules in `rbac'. Constraints are typically * used to prevent a process from transitioning to a new user * identity or role unless it is in a privileged type. * Constraints are likewise typically used to prevent a * process from labeling an object with a different user * identity. */ #ifndef _SEPOL_POLICYDB_CONSTRAINT_H_ #define _SEPOL_POLICYDB_CONSTRAINT_H_ #include #include #include #define CEXPR_MAXDEPTH 5 struct type_set; typedef struct constraint_expr { #define CEXPR_NOT 1 /* not expr */ #define CEXPR_AND 2 /* expr and expr */ #define CEXPR_OR 3 /* expr or expr */ #define CEXPR_ATTR 4 /* attr op attr */ #define CEXPR_NAMES 5 /* attr op names */ uint32_t expr_type; /* expression type */ #define CEXPR_USER 1 /* user */ #define CEXPR_ROLE 2 /* role */ #define CEXPR_TYPE 4 /* type */ #define CEXPR_TARGET 8 /* target if set, source otherwise */ #define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */ #define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */ #define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */ #define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */ #define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */ #define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */ #define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */ uint32_t attr; /* attribute */ #define CEXPR_EQ 1 /* == or eq */ #define CEXPR_NEQ 2 /* != */ #define CEXPR_DOM 3 /* dom */ #define CEXPR_DOMBY 4 /* domby */ #define CEXPR_INCOMP 5 /* incomp */ uint32_t op; /* operator */ ebitmap_t names; /* names */ struct type_set *type_names; struct constraint_expr *next; /* next expression */ } constraint_expr_t; typedef struct constraint_node { sepol_access_vector_t permissions; /* constrained permissions */ constraint_expr_t *expr; /* constraint on permissions */ struct constraint_node *next; /* next constraint */ } constraint_node_t; struct policydb; extern int constraint_expr_init(constraint_expr_t * expr); extern void constraint_expr_destroy(constraint_expr_t * expr); #endif /* _CONSTRAINT_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/context.h000066400000000000000000000042531223423440700214020ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A security context is a set of security attributes * associated with each subject and object controlled * by the security policy. Security contexts are * externally represented as variable-length strings * that can be interpreted by a user or application * with an understanding of the security policy. * Internally, the security server uses a simple * structure. This structure is private to the * security server and can be changed without affecting * clients of the security server. */ #ifndef _SEPOL_POLICYDB_CONTEXT_H_ #define _SEPOL_POLICYDB_CONTEXT_H_ #include #include #include /* * A security context consists of an authenticated user * identity, a role, a type and a MLS range. */ typedef struct context_struct { uint32_t user; uint32_t role; uint32_t type; mls_range_t range; } context_struct_t; static inline void mls_context_init(context_struct_t * c) { mls_range_init(&c->range); } static inline int mls_context_cpy(context_struct_t * dst, context_struct_t * src) { if (mls_range_cpy(&dst->range, &src->range) < 0) return -1; return 0; } static inline int mls_context_cmp(context_struct_t * c1, context_struct_t * c2) { return (mls_level_eq(&c1->range.level[0], &c2->range.level[0]) && mls_level_eq(&c1->range.level[1], &c2->range.level[1])); } static inline void mls_context_destroy(context_struct_t * c) { if (c == NULL) return; mls_range_destroy(&c->range); mls_context_init(c); } static inline void context_init(context_struct_t * c) { memset(c, 0, sizeof(*c)); } static inline int context_cpy(context_struct_t * dst, context_struct_t * src) { dst->user = src->user; dst->role = src->role; dst->type = src->type; return mls_context_cpy(dst, src); } static inline void context_destroy(context_struct_t * c) { if (c == NULL) return; c->user = c->role = c->type = 0; mls_context_destroy(c); } static inline int context_cmp(context_struct_t * c1, context_struct_t * c2) { return ((c1->user == c2->user) && (c1->role == c2->role) && (c1->type == c2->type) && mls_context_cmp(c1, c2)); } #endif libsepol-2.2/include/sepol/policydb/ebitmap.h000066400000000000000000000057351223423440700213450ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * An extensible bitmap is a bitmap that supports an * arbitrary number of bits. Extensible bitmaps are * used to represent sets of values, such as types, * roles, categories, and classes. * * Each extensible bitmap is implemented as a linked * list of bitmap nodes, where each bitmap node has * an explicitly specified starting bit position within * the total bitmap. */ #ifndef _SEPOL_POLICYDB_EBITMAP_H_ #define _SEPOL_POLICYDB_EBITMAP_H_ #include #include #define MAPTYPE uint64_t /* portion of bitmap in each node */ #define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */ #define MAPBIT 1ULL /* a bit in the node bitmap */ typedef struct ebitmap_node { uint32_t startbit; /* starting position in the total bitmap */ MAPTYPE map; /* this node's portion of the bitmap */ struct ebitmap_node *next; } ebitmap_node_t; typedef struct ebitmap { ebitmap_node_t *node; /* first node in the bitmap */ uint32_t highbit; /* highest position in the total bitmap */ } ebitmap_t; #define ebitmap_length(e) ((e)->highbit) #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) #define ebitmap_startnode(e) ((e)->node) static inline unsigned int ebitmap_start(const ebitmap_t * e, ebitmap_node_t ** n) { *n = e->node; return ebitmap_startbit(e); } static inline void ebitmap_init(ebitmap_t * e) { memset(e, 0, sizeof(*e)); } static inline unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit) { if ((bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next) { *n = (*n)->next; return (*n)->startbit; } return (bit + 1); } static inline int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit) { if (n->map & (MAPBIT << (bit - n->startbit))) return 1; return 0; } #define ebitmap_for_each_bit(e, n, bit) \ for (bit = ebitmap_start(e, &n); bit < ebitmap_length(e); bit = ebitmap_next(&n, bit)) \ extern int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2); extern int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2); extern int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1); extern int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2); extern int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2); extern int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit); extern int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit); extern unsigned int ebitmap_cardinality(ebitmap_t *e1); extern int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2); extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src); extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2); extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit); extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value); extern void ebitmap_destroy(ebitmap_t * e); extern int ebitmap_read(ebitmap_t * e, void *fp); #endif /* _EBITMAP_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/expand.h000066400000000000000000000070031223423440700211710ustar00rootroot00000000000000/* Authors: Jason Tang * Joshua Brindle * Karl MacMillan * * A set of utility functions that aid policy decision when dealing * with hierarchal items. * * Copyright (C) 2005 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 */ #ifndef _SEPOL_POLICYDB_EXPAND_H #define _SEPOL_POLICYDB_EXPAND_H #include #include #include /* * Expand only the avrules for a module. It is valid for this function * to expand base into itself (i.e. base == out); the typemap for * this special case should map type[i] to i+1. Likewise the boolmap * should map bool[i] to i + 1. This function optionally expands * neverallow rules. If neverallow rules are expanded, there is no * need to copy them and doing so could cause duplicate entries when * base == out. If the neverallow rules are not expanded, they are * just copied to the destination policy so that assertion checking * can be performed after expand. No assertion or hierarchy checking * is performed by this function. */ extern int expand_module_avrules(sepol_handle_t * handle, policydb_t * base, policydb_t * out, uint32_t * typemap, uint32_t * boolmap, uint32_t * rolemap, uint32_t * usermap, int verbose, int expand_neverallow); /* * Expand all parts of a module. Neverallow rules are not expanded (only * copied). It is not valid to expand base into itself. If check is non-zero, * performs hierarchy and assertion checking. */ extern int expand_module(sepol_handle_t * handle, policydb_t * base, policydb_t * out, int verbose, int check); extern int convert_type_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * typemap); extern int expand_convert_type_set(policydb_t * p, uint32_t * typemap, type_set_t * set, ebitmap_t * types, unsigned char alwaysexpand); extern int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, unsigned char alwaysexpand); extern int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap); extern int mls_semantic_level_expand(mls_semantic_level_t *sl, mls_level_t *l, policydb_t *p, sepol_handle_t *h); extern int mls_semantic_range_expand(mls_semantic_range_t *sr, mls_range_t *r, policydb_t *p, sepol_handle_t *h); extern int expand_rule(sepol_handle_t * handle, policydb_t * source_pol, avrule_t * source_rule, avtab_t * dest_avtab, cond_av_list_t ** cond, cond_av_list_t ** other, int enabled); extern int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa); extern int expand_cond_av_list(policydb_t * p, cond_av_list_t * l, cond_av_list_t ** newl, avtab_t * expa); #endif libsepol-2.2/include/sepol/policydb/flask.h000066400000000000000000000116001223423440700210100ustar00rootroot00000000000000/* This file is automatically generated. Do not edit. */ #ifndef _SEPOL_POLICYDB_FLASK_H_ #define _SEPOL_POLICYDB_FLASK_H_ /* * Security object class definitions */ #define SECCLASS_SECURITY 1 #define SECCLASS_PROCESS 2 #define SECCLASS_SYSTEM 3 #define SECCLASS_CAPABILITY 4 #define SECCLASS_FILESYSTEM 5 #define SECCLASS_FILE 6 #define SECCLASS_DIR 7 #define SECCLASS_FD 8 #define SECCLASS_LNK_FILE 9 #define SECCLASS_CHR_FILE 10 #define SECCLASS_BLK_FILE 11 #define SECCLASS_SOCK_FILE 12 #define SECCLASS_FIFO_FILE 13 #define SECCLASS_SOCKET 14 #define SECCLASS_TCP_SOCKET 15 #define SECCLASS_UDP_SOCKET 16 #define SECCLASS_RAWIP_SOCKET 17 #define SECCLASS_NODE 18 #define SECCLASS_NETIF 19 #define SECCLASS_NETLINK_SOCKET 20 #define SECCLASS_PACKET_SOCKET 21 #define SECCLASS_KEY_SOCKET 22 #define SECCLASS_UNIX_STREAM_SOCKET 23 #define SECCLASS_UNIX_DGRAM_SOCKET 24 #define SECCLASS_SEM 25 #define SECCLASS_MSG 26 #define SECCLASS_MSGQ 27 #define SECCLASS_SHM 28 #define SECCLASS_IPC 29 #define SECCLASS_PASSWD 30 #define SECCLASS_DRAWABLE 31 #define SECCLASS_WINDOW 32 #define SECCLASS_GC 33 #define SECCLASS_FONT 34 #define SECCLASS_COLORMAP 35 #define SECCLASS_PROPERTY 36 #define SECCLASS_CURSOR 37 #define SECCLASS_XCLIENT 38 #define SECCLASS_XINPUT 39 #define SECCLASS_XSERVER 40 #define SECCLASS_XEXTENSION 41 #define SECCLASS_PAX 42 #define SECCLASS_NETLINK_ROUTE_SOCKET 43 #define SECCLASS_NETLINK_FIREWALL_SOCKET 44 #define SECCLASS_NETLINK_TCPDIAG_SOCKET 45 #define SECCLASS_NETLINK_NFLOG_SOCKET 46 #define SECCLASS_NETLINK_XFRM_SOCKET 47 #define SECCLASS_NETLINK_SELINUX_SOCKET 48 #define SECCLASS_NETLINK_AUDIT_SOCKET 49 #define SECCLASS_NETLINK_IP6FW_SOCKET 50 #define SECCLASS_NETLINK_DNRT_SOCKET 51 #define SECCLASS_DBUS 52 /* * Security identifier indices for initial entities */ #define SECINITSID_KERNEL 1 #define SECINITSID_SECURITY 2 #define SECINITSID_UNLABELED 3 #define SECINITSID_FS 4 #define SECINITSID_FILE 5 #define SECINITSID_FILE_LABELS 6 #define SECINITSID_INIT 7 #define SECINITSID_ANY_SOCKET 8 #define SECINITSID_PORT 9 #define SECINITSID_NETIF 10 #define SECINITSID_NETMSG 11 #define SECINITSID_NODE 12 #define SECINITSID_IGMP_PACKET 13 #define SECINITSID_ICMP_SOCKET 14 #define SECINITSID_TCP_SOCKET 15 #define SECINITSID_SYSCTL_MODPROBE 16 #define SECINITSID_SYSCTL 17 #define SECINITSID_SYSCTL_FS 18 #define SECINITSID_SYSCTL_KERNEL 19 #define SECINITSID_SYSCTL_NET 20 #define SECINITSID_SYSCTL_NET_UNIX 21 #define SECINITSID_SYSCTL_VM 22 #define SECINITSID_SYSCTL_DEV 23 #define SECINITSID_KMOD 24 #define SECINITSID_POLICY 25 #define SECINITSID_SCMP_PACKET 26 #define SECINITSID_DEVNULL 27 #define SECINITSID_NUM 27 #endif libsepol-2.2/include/sepol/policydb/flask_types.h000066400000000000000000000032611223423440700222400ustar00rootroot00000000000000 /* -*- linux-c -*- */ /* * Author : Stephen Smalley, */ #ifndef _SEPOL_POLICYDB_FLASK_TYPES_H_ #define _SEPOL_POLICYDB_FLASK_TYPES_H_ /* * The basic Flask types and constants. */ #include #include /* * A security context is a set of security attributes * associated with each subject and object controlled * by the security policy. The security context type * is defined as a variable-length string that can be * interpreted by any application or user with an * understanding of the security policy. */ typedef char *sepol_security_context_t; /* * An access vector (AV) is a collection of related permissions * for a pair of SIDs. The bits within an access vector * are interpreted differently depending on the class of * the object. The access vector interpretations are specified * in flask/access_vectors, and the corresponding constants * for permissions are defined in the automatically generated * header file av_permissions.h. */ typedef uint32_t sepol_access_vector_t; /* * Each object class is identified by a fixed-size value. * The set of security classes is specified in flask/security_classes, * with the corresponding constants defined in the automatically * generated header file flask.h. */ typedef uint16_t sepol_security_class_t; #define SEPOL_SECCLASS_NULL 0x0000 /* no class */ #define SELINUX_MAGIC 0xf97cff8c #define SELINUX_MOD_MAGIC 0xf97cff8d typedef uint32_t sepol_security_id_t; #define SEPOL_SECSID_NULL 0 struct sepol_av_decision { sepol_access_vector_t allowed; sepol_access_vector_t decided; sepol_access_vector_t auditallow; sepol_access_vector_t auditdeny; uint32_t seqno; }; #endif libsepol-2.2/include/sepol/policydb/hashtab.h000066400000000000000000000102121223423440700213200ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A hash table (hashtab) maintains associations between * key values and datum values. The type of the key values * and the type of the datum values is arbitrary. The * functions for hash computation and key comparison are * provided by the creator of the table. */ #ifndef _SEPOL_POLICYDB_HASHTAB_H_ #define _SEPOL_POLICYDB_HASHTAB_H_ #include #include #include typedef char *hashtab_key_t; /* generic key type */ typedef void *hashtab_datum_t; /* generic datum type */ typedef struct hashtab_node *hashtab_ptr_t; typedef struct hashtab_node { hashtab_key_t key; hashtab_datum_t datum; hashtab_ptr_t next; } hashtab_node_t; typedef struct hashtab_val { hashtab_ptr_t *htable; /* hash table */ unsigned int size; /* number of slots in hash table */ uint32_t nel; /* number of elements in hash table */ unsigned int (*hash_value) (struct hashtab_val * h, hashtab_key_t key); /* hash function */ int (*keycmp) (struct hashtab_val * h, hashtab_key_t key1, hashtab_key_t key2); /* key comparison function */ } hashtab_val_t; typedef hashtab_val_t *hashtab_t; /* Creates a new hash table with the specified characteristics. Returns NULL if insufficent space is available or the new hash table otherwise. */ extern hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, const hashtab_key_t key), int (*keycmp) (hashtab_t h, const hashtab_key_t key1, const hashtab_key_t key2), unsigned int size); /* Inserts the specified (key, datum) pair into the specified hash table. Returns SEPOL_ENOMEM if insufficient space is available or SEPOL_EEXIST if there is already an entry with the same key or SEPOL_OK otherwise. */ extern int hashtab_insert(hashtab_t h, hashtab_key_t k, hashtab_datum_t d); /* Removes the entry with the specified key from the hash table. Applies the specified destroy function to (key,datum,args) for the entry. Returns SEPOL_ENOENT if no entry has the specified key or SEPOL_OK otherwise. */ extern int hashtab_remove(hashtab_t h, hashtab_key_t k, void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args); /* Insert or replace the specified (key, datum) pair in the specified hash table. If an entry for the specified key already exists, then the specified destroy function is applied to (key,datum,args) for the entry prior to replacing the entry's contents. Returns SEPOL_ENOMEM if insufficient space is available or SEPOL_OK otherwise. */ extern int hashtab_replace(hashtab_t h, hashtab_key_t k, hashtab_datum_t d, void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args); /* Searches for the entry with the specified key in the hash table. Returns NULL if no entry has the specified key or the datum of the entry otherwise. */ extern hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t k); /* Destroys the specified hash table. */ extern void hashtab_destroy(hashtab_t h); /* Applies the specified apply function to (key,datum,args) for each entry in the specified hash table. The order in which the function is applied to the entries is dependent upon the internal structure of the hash table. If apply returns a non-zero status, then hashtab_map will cease iterating through the hash table and will propagate the error return to its caller. */ extern int hashtab_map(hashtab_t h, int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args); /* Same as hashtab_map, except that if apply returns a non-zero status, then the (key,datum) pair will be removed from the hashtab and the destroy function will be applied to (key,datum,args). */ extern void hashtab_map_remove_on_error(hashtab_t h, int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args); extern void hashtab_hash_eval(hashtab_t h, char *tag); #endif libsepol-2.2/include/sepol/policydb/hierarchy.h000066400000000000000000000023301223423440700216660ustar00rootroot00000000000000/* Authors: Jason Tang * Joshua Brindle * Karl MacMillan * * A set of utility functions that aid policy decision when dealing * with hierarchal items. * * Copyright (C) 2005 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 */ #ifndef _SEPOL_POLICYDB_HIERARCHY_H_ #define _SEPOL_POLICYDB_HIERARCHY_H_ #include extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p); #endif libsepol-2.2/include/sepol/policydb/link.h000066400000000000000000000007001223423440700206440ustar00rootroot00000000000000/* Authors: Jason Tang * Joshua Brindle * Karl MacMillan */ #ifndef _SEPOL_POLICYDB_LINK_H #define _SEPOL_POLICYDB_LINK_H #include #include #include #include extern int link_modules(sepol_handle_t * handle, policydb_t * b, policydb_t ** mods, int len, int verbose); #endif libsepol-2.2/include/sepol/policydb/mls_types.h000066400000000000000000000103251223423440700217320ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * * 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 */ /* FLASK */ /* * Type definitions for the multi-level security (MLS) policy. */ #ifndef _SEPOL_POLICYDB_MLS_TYPES_H_ #define _SEPOL_POLICYDB_MLS_TYPES_H_ #include #include #include #include typedef struct mls_level { uint32_t sens; /* sensitivity */ ebitmap_t cat; /* category set */ } mls_level_t; typedef struct mls_range { mls_level_t level[2]; /* low == level[0], high == level[1] */ } mls_range_t; static inline int mls_level_cpy(struct mls_level *dst, struct mls_level *src) { dst->sens = src->sens; if (ebitmap_cpy(&dst->cat, &src->cat) < 0) return -1; return 0; } static inline void mls_level_init(struct mls_level *level) { memset(level, 0, sizeof(mls_level_t)); } static inline void mls_level_destroy(struct mls_level *level) { if (level == NULL) return; ebitmap_destroy(&level->cat); mls_level_init(level); } static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2) { return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); } static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2) { return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat)); } #define mls_level_incomp(l1, l2) \ (!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1))) #define mls_level_between(l1, l2, l3) \ (mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1))) #define mls_range_contains(r1, r2) \ (mls_level_dom(&(r2).level[0], &(r1).level[0]) && \ mls_level_dom(&(r1).level[1], &(r2).level[1])) static inline int mls_range_cpy(mls_range_t * dst, mls_range_t * src) { if (mls_level_cpy(&dst->level[0], &src->level[0]) < 0) goto err; if (mls_level_cpy(&dst->level[1], &src->level[1]) < 0) goto err_destroy; return 0; err_destroy: mls_level_destroy(&dst->level[0]); err: return -1; } static inline void mls_range_init(struct mls_range *r) { mls_level_init(&r->level[0]); mls_level_init(&r->level[1]); } static inline void mls_range_destroy(struct mls_range *r) { mls_level_destroy(&r->level[0]); mls_level_destroy(&r->level[1]); } static inline int mls_range_eq(struct mls_range *r1, struct mls_range *r2) { return (mls_level_eq(&r1->level[0], &r2->level[0]) && mls_level_eq(&r1->level[1], &r2->level[1])); } typedef struct mls_semantic_cat { uint32_t low; /* first bit this struct represents */ uint32_t high; /* last bit represented - equals low for a single cat */ struct mls_semantic_cat *next; } mls_semantic_cat_t; typedef struct mls_semantic_level { uint32_t sens; mls_semantic_cat_t *cat; } mls_semantic_level_t; typedef struct mls_semantic_range { mls_semantic_level_t level[2]; } mls_semantic_range_t; extern void mls_semantic_cat_init(mls_semantic_cat_t *c); extern void mls_semantic_cat_destroy(mls_semantic_cat_t *c); extern void mls_semantic_level_init(mls_semantic_level_t *l); extern void mls_semantic_level_destroy(mls_semantic_level_t *l); extern int mls_semantic_level_cpy(mls_semantic_level_t *dst, mls_semantic_level_t *src); extern void mls_semantic_range_init(mls_semantic_range_t *r); extern void mls_semantic_range_destroy(mls_semantic_range_t *r); extern int mls_semantic_range_cpy(mls_semantic_range_t *dst, mls_semantic_range_t *src); #endif libsepol-2.2/include/sepol/policydb/module.h000066400000000000000000000026671223423440700212120ustar00rootroot00000000000000/* Author: Karl MacMillan * * Copyright (C) 2004-2005 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 */ #ifndef _SEPOL_POLICYDB_MODULE_H_ #define _SEPOL_POLICYDB_MODULE_H_ #include #include #include #include #include #define SEPOL_MODULE_PACKAGE_MAGIC 0xf97cff8f struct sepol_module_package { sepol_policydb_t *policy; uint32_t version; char *file_contexts; size_t file_contexts_len; char *seusers; size_t seusers_len; char *user_extra; size_t user_extra_len; char *netfilter_contexts; size_t netfilter_contexts_len; }; extern int sepol_module_package_init(sepol_module_package_t * p); #endif libsepol-2.2/include/sepol/policydb/polcaps.h000066400000000000000000000011331223423440700213510ustar00rootroot00000000000000#ifndef _SEPOL_POLICYDB_POLCAPS_H_ #define _SEPOL_POLICYDB_POLCAPS_H_ /* Policy capabilities */ enum { POLICYDB_CAPABILITY_NETPEER, POLICYDB_CAPABILITY_OPENPERM, POLICYDB_CAPABILITY_REDHAT1, /* reserved for RH testing of ptrace_child */ POLICYDB_CAPABILITY_ALWAYSNETWORK, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) /* Convert a capability name to number. */ extern int sepol_polcap_getnum(const char *name); /* Convert a capability number to name. */ extern const char *sepol_polcap_getname(int capnum); #endif /* _SEPOL_POLICYDB_POLCAPS_H_ */ libsepol-2.2/include/sepol/policydb/policydb.h000066400000000000000000000566471223423440700215410ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Joshua Brindle * Karl MacMillan * Jason Tang * * Module support * * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * * Updated: Red Hat, Inc. James Morris * * Fine-grained netlink support * IPv6 support * Code cleanup * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2003 - 2004 Red Hat, Inc. * * 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 */ /* FLASK */ /* * A policy database (policydb) specifies the * configuration data for the security policy. */ #ifndef _SEPOL_POLICYDB_POLICYDB_H_ #define _SEPOL_POLICYDB_POLICYDB_H_ #include #include #include #include #include #include #include #include #include #define ERRMSG_LEN 1024 #define POLICYDB_SUCCESS 0 #define POLICYDB_ERROR -1 #define POLICYDB_UNSUPPORTED -2 /* * A datum type is defined for each kind of symbol * in the configuration data: individual permissions, * common prefixes for access vectors, classes, * users, roles, types, sensitivities, categories, etc. */ /* type set preserves data needed by modules such as *, ~ and attributes */ typedef struct type_set { ebitmap_t types; ebitmap_t negset; #define TYPE_STAR 1 #define TYPE_COMP 2 uint32_t flags; } type_set_t; typedef struct role_set { ebitmap_t roles; #define ROLE_STAR 1 #define ROLE_COMP 2 uint32_t flags; } role_set_t; /* Permission attributes */ typedef struct perm_datum { symtab_datum_t s; } perm_datum_t; /* Attributes of a common prefix for access vectors */ typedef struct common_datum { symtab_datum_t s; symtab_t permissions; /* common permissions */ } common_datum_t; /* Class attributes */ typedef struct class_datum { symtab_datum_t s; char *comkey; /* common name */ common_datum_t *comdatum; /* common datum */ symtab_t permissions; /* class-specific permission symbol table */ constraint_node_t *constraints; /* constraints on class permissions */ constraint_node_t *validatetrans; /* special transition rules */ /* Options how a new object user and role should be decided */ #define DEFAULT_SOURCE 1 #define DEFAULT_TARGET 2 char default_user; char default_role; char default_type; /* Options how a new object range should be decided */ #define DEFAULT_SOURCE_LOW 1 #define DEFAULT_SOURCE_HIGH 2 #define DEFAULT_SOURCE_LOW_HIGH 3 #define DEFAULT_TARGET_LOW 4 #define DEFAULT_TARGET_HIGH 5 #define DEFAULT_TARGET_LOW_HIGH 6 char default_range; } class_datum_t; /* Role attributes */ typedef struct role_datum { symtab_datum_t s; ebitmap_t dominates; /* set of roles dominated by this role */ type_set_t types; /* set of authorized types for role */ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */ uint32_t bounds; /* bounds role, if exist */ #define ROLE_ROLE 0 /* regular role in kernel policies */ #define ROLE_ATTRIB 1 /* attribute */ uint32_t flavor; ebitmap_t roles; /* roles with this attribute */ } role_datum_t; typedef struct role_trans { uint32_t role; /* current role */ uint32_t type; /* program executable type, or new object type */ uint32_t tclass; /* process class, or new object class */ uint32_t new_role; /* new role */ struct role_trans *next; } role_trans_t; typedef struct role_allow { uint32_t role; /* current role */ uint32_t new_role; /* new role */ struct role_allow *next; } role_allow_t; /* filename_trans rules */ typedef struct filename_trans { uint32_t stype; uint32_t ttype; uint32_t tclass; char *name; uint32_t otype; struct filename_trans *next; } filename_trans_t; /* Type attributes */ typedef struct type_datum { symtab_datum_t s; uint32_t primary; /* primary name? can be set to primary value if below is TYPE_ */ #define TYPE_TYPE 0 /* regular type or alias in kernel policies */ #define TYPE_ATTRIB 1 /* attribute */ #define TYPE_ALIAS 2 /* alias in modular policy */ uint32_t flavor; ebitmap_t types; /* types with this attribute */ #define TYPE_FLAGS_PERMISSIVE 0x01 uint32_t flags; uint32_t bounds; /* bounds type, if exist */ } type_datum_t; /* * Properties of type_datum * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY */ #define TYPEDATUM_PROPERTY_PRIMARY 0x0001 #define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002 #define TYPEDATUM_PROPERTY_ALIAS 0x0004 /* userspace only */ #define TYPEDATUM_PROPERTY_PERMISSIVE 0x0008 /* userspace only */ /* User attributes */ typedef struct user_datum { symtab_datum_t s; role_set_t roles; /* set of authorized roles for user */ mls_semantic_range_t range; /* MLS range (min. - max.) for user */ mls_semantic_level_t dfltlevel; /* default login MLS level for user */ ebitmap_t cache; /* This is an expanded set used for context validation during parsing */ mls_range_t exp_range; /* expanded range used for validation */ mls_level_t exp_dfltlevel; /* expanded range used for validation */ uint32_t bounds; /* bounds user, if exist */ } user_datum_t; /* Sensitivity attributes */ typedef struct level_datum { mls_level_t *level; /* sensitivity and associated categories */ unsigned char isalias; /* is this sensitivity an alias for another? */ unsigned char defined; } level_datum_t; /* Category attributes */ typedef struct cat_datum { symtab_datum_t s; unsigned char isalias; /* is this category an alias for another? */ } cat_datum_t; typedef struct range_trans { uint32_t source_type; uint32_t target_type; uint32_t target_class; mls_range_t target_range; struct range_trans *next; } range_trans_t; /* Boolean data type */ typedef struct cond_bool_datum { symtab_datum_t s; int state; #define COND_BOOL_FLAGS_TUNABLE 0x01 /* is this a tunable? */ uint32_t flags; } cond_bool_datum_t; struct cond_node; typedef struct cond_node cond_list_t; struct cond_av_list; typedef struct class_perm_node { uint32_t class; uint32_t data; /* permissions or new type */ struct class_perm_node *next; } class_perm_node_t; typedef struct avrule { /* these typedefs are almost exactly the same as those in avtab.h - they are * here because of the need to include neverallow and dontaudit messages */ #define AVRULE_ALLOWED 1 #define AVRULE_AUDITALLOW 2 #define AVRULE_AUDITDENY 4 #define AVRULE_DONTAUDIT 8 #define AVRULE_NEVERALLOW 128 #define AVRULE_AV (AVRULE_ALLOWED | AVRULE_AUDITALLOW | AVRULE_AUDITDENY | AVRULE_DONTAUDIT | AVRULE_NEVERALLOW) #define AVRULE_TRANSITION 16 #define AVRULE_MEMBER 32 #define AVRULE_CHANGE 64 #define AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE) uint32_t specified; #define RULE_SELF 1 uint32_t flags; type_set_t stypes; type_set_t ttypes; class_perm_node_t *perms; unsigned long line; /* line number from policy.conf where * this rule originated */ struct avrule *next; } avrule_t; typedef struct role_trans_rule { role_set_t roles; /* current role */ type_set_t types; /* program executable type, or new object type */ ebitmap_t classes; /* process class, or new object class */ uint32_t new_role; /* new role */ struct role_trans_rule *next; } role_trans_rule_t; typedef struct role_allow_rule { role_set_t roles; /* current role */ role_set_t new_roles; /* new roles */ struct role_allow_rule *next; } role_allow_rule_t; typedef struct filename_trans_rule { type_set_t stypes; type_set_t ttypes; uint32_t tclass; char *name; uint32_t otype; /* new type */ struct filename_trans_rule *next; } filename_trans_rule_t; typedef struct range_trans_rule { type_set_t stypes; type_set_t ttypes; ebitmap_t tclasses; mls_semantic_range_t trange; struct range_trans_rule *next; } range_trans_rule_t; /* * The configuration data includes security contexts for * initial SIDs, unlabeled file systems, TCP and UDP port numbers, * network interfaces, and nodes. This structure stores the * relevant data for one such entry. Entries of the same kind * (e.g. all initial SIDs) are linked together into a list. */ typedef struct ocontext { union { char *name; /* name of initial SID, fs, netif, fstype, path */ struct { uint8_t protocol; uint16_t low_port; uint16_t high_port; } port; /* TCP or UDP port information */ struct { uint32_t addr; /* network order */ uint32_t mask; /* network order */ } node; /* node information */ struct { uint32_t addr[4]; /* network order */ uint32_t mask[4]; /* network order */ } node6; /* IPv6 node information */ uint32_t device; uint16_t pirq; struct { uint32_t low_iomem; uint32_t high_iomem; } iomem; struct { uint32_t low_ioport; uint32_t high_ioport; } ioport; } u; union { uint32_t sclass; /* security class for genfs */ uint32_t behavior; /* labeling behavior for fs_use */ } v; context_struct_t context[2]; /* security context(s) */ sepol_security_id_t sid[2]; /* SID(s) */ struct ocontext *next; } ocontext_t; typedef struct genfs { char *fstype; struct ocontext *head; struct genfs *next; } genfs_t; /* symbol table array indices */ #define SYM_COMMONS 0 #define SYM_CLASSES 1 #define SYM_ROLES 2 #define SYM_TYPES 3 #define SYM_USERS 4 #define SYM_BOOLS 5 #define SYM_LEVELS 6 #define SYM_CATS 7 #define SYM_NUM 8 /* object context array indices */ #define OCON_ISID 0 /* initial SIDs */ #define OCON_FS 1 /* unlabeled file systems */ #define OCON_PORT 2 /* TCP and UDP port numbers */ #define OCON_NETIF 3 /* network interfaces */ #define OCON_NODE 4 /* nodes */ #define OCON_FSUSE 5 /* fs_use */ #define OCON_NODE6 6 /* IPv6 nodes */ #define OCON_GENFS 7 /* needed for ocontext_supported */ /* object context array indices for Xen */ #define OCON_XEN_ISID 0 /* initial SIDs */ #define OCON_XEN_PIRQ 1 /* physical irqs */ #define OCON_XEN_IOPORT 2 /* io ports */ #define OCON_XEN_IOMEM 3 /* io memory */ #define OCON_XEN_PCIDEVICE 4 /* pci devices */ /* OCON_NUM needs to be the largest index in any platform's ocontext array */ #define OCON_NUM 7 /* section: module information */ /* scope_index_t holds all of the symbols that are in scope in a * particular situation. The bitmaps are indices (and thus must * subtract one) into the global policydb->scope array. */ typedef struct scope_index { ebitmap_t scope[SYM_NUM]; #define p_classes_scope scope[SYM_CLASSES] #define p_roles_scope scope[SYM_ROLES] #define p_types_scope scope[SYM_TYPES] #define p_users_scope scope[SYM_USERS] #define p_bools_scope scope[SYM_BOOLS] #define p_sens_scope scope[SYM_LEVELS] #define p_cat_scope scope[SYM_CATS] /* this array maps from class->value to the permissions within * scope. if bit (perm->value - 1) is set in map * class_perms_map[class->value - 1] then that permission is * enabled for this class within this decl. */ ebitmap_t *class_perms_map; /* total number of classes in class_perms_map array */ uint32_t class_perms_len; } scope_index_t; /* a list of declarations for a particular avrule_decl */ /* These two structs declare a block of policy that has TE and RBAC * statements and declarations. The root block (the global policy) * can never have an ELSE branch. */ typedef struct avrule_decl { uint32_t decl_id; uint32_t enabled; /* whether this block is enabled */ cond_list_t *cond_list; avrule_t *avrules; role_trans_rule_t *role_tr_rules; role_allow_rule_t *role_allow_rules; range_trans_rule_t *range_tr_rules; scope_index_t required; /* symbols needed to activate this block */ scope_index_t declared; /* symbols declared within this block */ /* type transition rules with a 'name' component */ filename_trans_rule_t *filename_trans_rules; /* for additive statements (type attribute, roles, and users) */ symtab_t symtab[SYM_NUM]; /* In a linked module this will contain the name of the module * from which this avrule_decl originated. */ char *module_name; struct avrule_decl *next; } avrule_decl_t; typedef struct avrule_block { avrule_decl_t *branch_list; avrule_decl_t *enabled; /* pointer to which branch is enabled. this is used in linking and never written to disk */ #define AVRULE_OPTIONAL 1 uint32_t flags; /* any flags for this block, currently just optional */ struct avrule_block *next; } avrule_block_t; /* Every identifier has its own scope datum. The datum describes if * the item is to be included into the final policy during * expansion. */ typedef struct scope_datum { /* Required for this decl */ #define SCOPE_REQ 1 /* Declared in this decl */ #define SCOPE_DECL 2 uint32_t scope; uint32_t *decl_ids; uint32_t decl_ids_len; /* decl_ids is a list of avrule_decl's that declare/require * this symbol. If scope==SCOPE_DECL then this is a list of * declarations. If the symbol may only be declared once * (types, bools) then decl_ids_len will be exactly 1. For * implicitly declared things (roles, users) then decl_ids_len * will be at least 1. */ } scope_datum_t; /* The policy database */ typedef struct policydb { #define POLICY_KERN SEPOL_POLICY_KERN #define POLICY_BASE SEPOL_POLICY_BASE #define POLICY_MOD SEPOL_POLICY_MOD uint32_t policy_type; char *name; char *version; int target_platform; /* Set when the policydb is modified such that writing is unsupported */ int unsupported_format; /* Whether this policydb is mls, should always be set */ int mls; /* symbol tables */ symtab_t symtab[SYM_NUM]; #define p_commons symtab[SYM_COMMONS] #define p_classes symtab[SYM_CLASSES] #define p_roles symtab[SYM_ROLES] #define p_types symtab[SYM_TYPES] #define p_users symtab[SYM_USERS] #define p_bools symtab[SYM_BOOLS] #define p_levels symtab[SYM_LEVELS] #define p_cats symtab[SYM_CATS] /* symbol names indexed by (value - 1) */ char **sym_val_to_name[SYM_NUM]; #define p_common_val_to_name sym_val_to_name[SYM_COMMONS] #define p_class_val_to_name sym_val_to_name[SYM_CLASSES] #define p_role_val_to_name sym_val_to_name[SYM_ROLES] #define p_type_val_to_name sym_val_to_name[SYM_TYPES] #define p_user_val_to_name sym_val_to_name[SYM_USERS] #define p_bool_val_to_name sym_val_to_name[SYM_BOOLS] #define p_sens_val_to_name sym_val_to_name[SYM_LEVELS] #define p_cat_val_to_name sym_val_to_name[SYM_CATS] /* class, role, and user attributes indexed by (value - 1) */ class_datum_t **class_val_to_struct; role_datum_t **role_val_to_struct; user_datum_t **user_val_to_struct; type_datum_t **type_val_to_struct; /* module stuff section -- used in parsing and for modules */ /* keep track of the scope for every identifier. these are * hash tables, where the key is the identifier name and value * a scope_datum_t. as a convenience, one may use the * p_*_macros (cf. struct scope_index_t declaration). */ symtab_t scope[SYM_NUM]; /* module rule storage */ avrule_block_t *global; /* avrule_decl index used for link/expand */ avrule_decl_t **decl_val_to_struct; /* compiled storage of rules - use for the kernel policy */ /* type enforcement access vectors and transitions */ avtab_t te_avtab; /* bools indexed by (value - 1) */ cond_bool_datum_t **bool_val_to_struct; /* type enforcement conditional access vectors and transitions */ avtab_t te_cond_avtab; /* linked list indexing te_cond_avtab by conditional */ cond_list_t *cond_list; /* role transitions */ role_trans_t *role_tr; /* type transition rules with a 'name' component */ filename_trans_t *filename_trans; /* role allows */ role_allow_t *role_allow; /* security contexts of initial SIDs, unlabeled file systems, TCP or UDP port numbers, network interfaces and nodes */ ocontext_t *ocontexts[OCON_NUM]; /* security contexts for files in filesystems that cannot support a persistent label mapping or use another fixed labeling behavior. */ genfs_t *genfs; /* range transitions */ range_trans_t *range_tr; ebitmap_t *type_attr_map; ebitmap_t *attr_type_map; /* not saved in the binary policy */ ebitmap_t policycaps; /* this bitmap is referenced by type NOT the typical type-1 used in other bitmaps. Someday the 0 bit may be used for global permissive */ ebitmap_t permissive_map; unsigned policyvers; unsigned handle_unknown; } policydb_t; struct sepol_policydb { struct policydb p; }; extern int policydb_init(policydb_t * p); extern int policydb_from_image(sepol_handle_t * handle, void *data, size_t len, policydb_t * policydb); extern int policydb_to_image(sepol_handle_t * handle, policydb_t * policydb, void **newdata, size_t * newlen); extern int policydb_index_classes(policydb_t * p); extern int policydb_index_bools(policydb_t * p); extern int policydb_index_others(sepol_handle_t * handle, policydb_t * p, unsigned int verbose); extern int policydb_reindex_users(policydb_t * p); extern void policydb_destroy(policydb_t * p); extern int policydb_load_isids(policydb_t * p, sidtab_t * s); /* Deprecated */ extern int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c); extern void symtabs_destroy(symtab_t * symtab); extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p); typedef void (*hashtab_destroy_func_t) (hashtab_key_t k, hashtab_datum_t d, void *args); extern hashtab_destroy_func_t get_symtab_destroy_func(int sym_num); extern void class_perm_node_init(class_perm_node_t * x); extern void type_set_init(type_set_t * x); extern void type_set_destroy(type_set_t * x); extern int type_set_cpy(type_set_t * dst, type_set_t * src); extern int type_set_or_eq(type_set_t * dst, type_set_t * other); extern void role_set_init(role_set_t * x); extern void role_set_destroy(role_set_t * x); extern void avrule_init(avrule_t * x); extern void avrule_destroy(avrule_t * x); extern void avrule_list_destroy(avrule_t * x); extern void role_trans_rule_init(role_trans_rule_t * x); extern void role_trans_rule_list_destroy(role_trans_rule_t * x); extern void filename_trans_rule_init(filename_trans_rule_t * x); extern void filename_trans_rule_list_destroy(filename_trans_rule_t * x); extern void role_datum_init(role_datum_t * x); extern void role_datum_destroy(role_datum_t * x); extern void role_allow_rule_init(role_allow_rule_t * x); extern void role_allow_rule_destroy(role_allow_rule_t * x); extern void role_allow_rule_list_destroy(role_allow_rule_t * x); extern void range_trans_rule_init(range_trans_rule_t *x); extern void range_trans_rule_destroy(range_trans_rule_t *x); extern void range_trans_rule_list_destroy(range_trans_rule_t *x); extern void type_datum_init(type_datum_t * x); extern void type_datum_destroy(type_datum_t * x); extern void user_datum_init(user_datum_t * x); extern void user_datum_destroy(user_datum_t * x); extern void level_datum_init(level_datum_t * x); extern void level_datum_destroy(level_datum_t * x); extern void cat_datum_init(cat_datum_t * x); extern void cat_datum_destroy(cat_datum_t * x); extern int check_assertions(sepol_handle_t * handle, policydb_t * p, avrule_t * avrules); extern int symtab_insert(policydb_t * x, uint32_t sym, hashtab_key_t key, hashtab_datum_t datum, uint32_t scope, uint32_t avrule_decl_id, uint32_t * value); /* A policy "file" may be a memory region referenced by a (data, len) pair or a file referenced by a FILE pointer. */ typedef struct policy_file { #define PF_USE_MEMORY 0 #define PF_USE_STDIO 1 #define PF_LEN 2 /* total up length in len field */ unsigned type; char *data; size_t len; size_t size; FILE *fp; struct sepol_handle *handle; } policy_file_t; struct sepol_policy_file { struct policy_file pf; }; extern void policy_file_init(policy_file_t * x); extern int policydb_read(policydb_t * p, struct policy_file *fp, unsigned int verbose); extern int avrule_read_list(policydb_t * p, avrule_t ** avrules, struct policy_file *fp); extern int policydb_write(struct policydb *p, struct policy_file *pf); extern int policydb_set_target_platform(policydb_t *p, int platform); #define PERM_SYMTAB_SIZE 32 /* Identify specific policy version changes */ #define POLICYDB_VERSION_BASE 15 #define POLICYDB_VERSION_BOOL 16 #define POLICYDB_VERSION_IPV6 17 #define POLICYDB_VERSION_NLCLASS 18 #define POLICYDB_VERSION_VALIDATETRANS 19 #define POLICYDB_VERSION_MLS 19 #define POLICYDB_VERSION_AVTAB 20 #define POLICYDB_VERSION_RANGETRANS 21 #define POLICYDB_VERSION_POLCAP 22 #define POLICYDB_VERSION_PERMISSIVE 23 #define POLICYDB_VERSION_BOUNDARY 24 #define POLICYDB_VERSION_FILENAME_TRANS 25 #define POLICYDB_VERSION_ROLETRANS 26 #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES /* Module versions and specific changes*/ #define MOD_POLICYDB_VERSION_BASE 4 #define MOD_POLICYDB_VERSION_VALIDATETRANS 5 #define MOD_POLICYDB_VERSION_MLS 5 #define MOD_POLICYDB_VERSION_RANGETRANS 6 #define MOD_POLICYDB_VERSION_MLS_USERS 6 #define MOD_POLICYDB_VERSION_POLCAP 7 #define MOD_POLICYDB_VERSION_PERMISSIVE 8 #define MOD_POLICYDB_VERSION_BOUNDARY 9 #define MOD_POLICYDB_VERSION_BOUNDARY_ALIAS 10 #define MOD_POLICYDB_VERSION_FILENAME_TRANS 11 #define MOD_POLICYDB_VERSION_ROLETRANS 12 #define MOD_POLICYDB_VERSION_ROLEATTRIB 13 #define MOD_POLICYDB_VERSION_TUNABLE_SEP 14 #define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 15 #define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16 #define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES 17 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE #define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES #define POLICYDB_CONFIG_MLS 1 /* macros to check policy feature */ /* TODO: add other features here */ #define policydb_has_boundary_feature(p) \ (((p)->policy_type == POLICY_KERN \ && p->policyvers >= POLICYDB_VERSION_BOUNDARY) || \ ((p)->policy_type != POLICY_KERN \ && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)) /* the config flags related to unknown classes/perms are bits 2 and 3 */ #define DENY_UNKNOWN SEPOL_DENY_UNKNOWN #define REJECT_UNKNOWN SEPOL_REJECT_UNKNOWN #define ALLOW_UNKNOWN SEPOL_ALLOW_UNKNOWN #define POLICYDB_CONFIG_UNKNOWN_MASK (DENY_UNKNOWN | REJECT_UNKNOWN | ALLOW_UNKNOWN) #define OBJECT_R "object_r" #define OBJECT_R_VAL 1 #define POLICYDB_MAGIC SELINUX_MAGIC #define POLICYDB_STRING "SE Linux" #define POLICYDB_XEN_STRING "XenFlask" #define POLICYDB_STRING_MAX_LENGTH 32 #define POLICYDB_MOD_MAGIC SELINUX_MOD_MAGIC #define POLICYDB_MOD_STRING "SE Linux Module" #define SEPOL_TARGET_SELINUX 0 #define SEPOL_TARGET_XEN 1 #endif /* _POLICYDB_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/services.h000066400000000000000000000166101223423440700215410ustar00rootroot00000000000000 /* -*- linux-c -*- */ /* * Author : Stephen Smalley, */ #ifndef _SEPOL_POLICYDB_SERVICES_H_ #define _SEPOL_POLICYDB_SERVICES_H_ /* * Security server interface. */ #include #include #include /* Set the policydb and sidtab structures to be used by the service functions. If not set, then these default to private structures within libsepol that can only be initialized and accessed via the service functions themselves. Setting the structures explicitly allows a program to directly manipulate them, e.g. checkpolicy populates the structures directly from a source policy rather than from a binary policy. */ extern int sepol_set_policydb(policydb_t * p); extern int sepol_set_sidtab(sidtab_t * s); /* Modify a policydb for boolean settings. */ int sepol_genbools_policydb(policydb_t * policydb, const char *booleans); /* Modify a policydb for user settings. */ int sepol_genusers_policydb(policydb_t * policydb, const char *usersdir); /* Load the security policy. This initializes the policydb and sidtab based on the provided binary policy. */ extern int sepol_load_policy(void *data, size_t len); /* * Compute access vectors based on a SID pair for * the permissions in a particular class. */ extern int sepol_compute_av(sepol_security_id_t ssid, /* IN */ sepol_security_id_t tsid, /* IN */ sepol_security_class_t tclass, /* IN */ sepol_access_vector_t requested, /* IN */ struct sepol_av_decision *avd); /* OUT */ /* Same as above, but also return the reason(s) for any denials of the requested permissions. */ #define SEPOL_COMPUTEAV_TE 1 #define SEPOL_COMPUTEAV_CONS 2 #define SEPOL_COMPUTEAV_RBAC 4 extern int sepol_compute_av_reason(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, unsigned int *reason); /* * Same as above, but also returns the constraint expression calculations * whether allowed or denied in a buffer. This buffer is allocated by * this call and must be free'd by the caller using free(3). The contraint * buffer will contain any constraints in infix notation. * If the SHOW_GRANTED flag is set it will show granted and denied * constraints. The default is to show only denied constraints. */ #define SHOW_GRANTED 1 extern int sepol_compute_av_reason_buffer(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, unsigned int *reason, char **reason_buf, unsigned int flags); /* * Return a class ID associated with the class string representation * specified by `class_name'. */ extern int sepol_string_to_security_class(const char *class_name, sepol_security_class_t *tclass); /* * Return a permission av bit associated with tclass and the string * representation of the `perm_name'. */ extern int sepol_string_to_av_perm(sepol_security_class_t tclass, const char *perm_name, sepol_access_vector_t *av); /* * Compute a SID to use for labeling a new object in the * class `tclass' based on a SID pair. */ extern int sepol_transition_sid(sepol_security_id_t ssid, /* IN */ sepol_security_id_t tsid, /* IN */ sepol_security_class_t tclass, /* IN */ sepol_security_id_t * out_sid); /* OUT */ /* * Compute a SID to use when selecting a member of a * polyinstantiated object of class `tclass' based on * a SID pair. */ extern int sepol_member_sid(sepol_security_id_t ssid, /* IN */ sepol_security_id_t tsid, /* IN */ sepol_security_class_t tclass, /* IN */ sepol_security_id_t * out_sid); /* OUT */ /* * Compute a SID to use for relabeling an object in the * class `tclass' based on a SID pair. */ extern int sepol_change_sid(sepol_security_id_t ssid, /* IN */ sepol_security_id_t tsid, /* IN */ sepol_security_class_t tclass, /* IN */ sepol_security_id_t * out_sid); /* OUT */ /* * Write the security context string representation of * the context associated with `sid' into a dynamically * allocated string of the correct size. Set `*scontext' * to point to this string and set `*scontext_len' to * the length of the string. */ extern int sepol_sid_to_context(sepol_security_id_t sid, /* IN */ sepol_security_context_t * scontext, /* OUT */ size_t * scontext_len); /* OUT */ /* * Return a SID associated with the security context that * has the string representation specified by `scontext'. */ extern int sepol_context_to_sid(const sepol_security_context_t scontext, /* IN */ size_t scontext_len, /* IN */ sepol_security_id_t * out_sid); /* OUT */ /* * Generate the set of SIDs for legal security contexts * for a given user that can be reached by `fromsid'. * Set `*sids' to point to a dynamically allocated * array containing the set of SIDs. Set `*nel' to the * number of elements in the array. */ extern int sepol_get_user_sids(sepol_security_id_t callsid, char *username, sepol_security_id_t ** sids, uint32_t * nel); /* * Return the SIDs to use for an unlabeled file system * that is being mounted from the device with the * the kdevname `name'. The `fs_sid' SID is returned for * the file system and the `file_sid' SID is returned * for all files within that file system. */ extern int sepol_fs_sid(char *dev, /* IN */ sepol_security_id_t * fs_sid, /* OUT */ sepol_security_id_t * file_sid); /* OUT */ /* * Return the SID of the port specified by * `domain', `type', `protocol', and `port'. */ extern int sepol_port_sid(uint16_t domain, uint16_t type, uint8_t protocol, uint16_t port, sepol_security_id_t * out_sid); /* * Return the SIDs to use for a network interface * with the name `name'. The `if_sid' SID is returned for * the interface and the `msg_sid' SID is returned as * the default SID for messages received on the * interface. */ extern int sepol_netif_sid(char *name, sepol_security_id_t * if_sid, sepol_security_id_t * msg_sid); /* * Return the SID of the node specified by the address * `addr' where `addrlen' is the length of the address * in bytes and `domain' is the communications domain or * address family in which the address should be interpreted. */ extern int sepol_node_sid(uint16_t domain, void *addr, size_t addrlen, sepol_security_id_t * out_sid); /* * Return a value indicating how to handle labeling for the * the specified filesystem type, and optionally return a SID * for the filesystem object. */ #define SECURITY_FS_USE_XATTR 1 /* use xattr */ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ #define SECURITY_FS_USE_GENFS 4 /* use the genfs support */ #define SECURITY_FS_USE_NONE 5 /* no labeling support */ extern int sepol_fs_use(const char *fstype, /* IN */ unsigned int *behavior, /* OUT */ sepol_security_id_t * sid); /* OUT */ /* * Return the SID to use for a file in a filesystem * that cannot support a persistent label mapping or use another * fixed labeling behavior like transition SIDs or task SIDs. */ extern int sepol_genfs_sid(const char *fstype, /* IN */ char *name, /* IN */ sepol_security_class_t sclass, /* IN */ sepol_security_id_t * sid); /* OUT */ #endif libsepol-2.2/include/sepol/policydb/sidtab.h000066400000000000000000000035651223423440700211710ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A security identifier table (sidtab) is a hash table * of security context structures indexed by SID value. */ #ifndef _SEPOL_POLICYDB_SIDTAB_H_ #define _SEPOL_POLICYDB_SIDTAB_H_ #include typedef struct sidtab_node { sepol_security_id_t sid; /* security identifier */ context_struct_t context; /* security context structure */ struct sidtab_node *next; } sidtab_node_t; typedef struct sidtab_node *sidtab_ptr_t; #define SIDTAB_HASH_BITS 7 #define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) #define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) #define SIDTAB_SIZE SIDTAB_HASH_BUCKETS typedef struct { sidtab_ptr_t *htable; unsigned int nel; /* number of elements */ unsigned int next_sid; /* next SID to allocate */ unsigned char shutdown; } sidtab_t; extern int sepol_sidtab_init(sidtab_t * s); extern int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid, context_struct_t * context); extern context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid); extern int sepol_sidtab_map(sidtab_t * s, int (*apply) (sepol_security_id_t sid, context_struct_t * context, void *args), void *args); extern void sepol_sidtab_map_remove_on_error(sidtab_t * s, int (*apply) (sepol_security_id_t s, context_struct_t * context, void *args), void *args); extern int sepol_sidtab_context_to_sid(sidtab_t * s, /* IN */ context_struct_t * context, /* IN */ sepol_security_id_t * sid); /* OUT */ extern void sepol_sidtab_hash_eval(sidtab_t * h, char *tag); extern void sepol_sidtab_destroy(sidtab_t * s); extern void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src); extern void sepol_sidtab_shutdown(sidtab_t * s); #endif /* _SIDTAB_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/symtab.h000066400000000000000000000020121223423440700212040ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * A symbol table (symtab) maintains associations between symbol * strings and datum values. The type of the datum values * is arbitrary. The symbol table type is implemented * using the hash table type (hashtab). */ #ifndef _SEPOL_POLICYDB_SYMTAB_H_ #define _SEPOL_POLICYDB_SYMTAB_H_ #include /* The symtab_datum struct stores the common information for * all symtab datums. It should the first element in every * struct that will be used in a symtab to allow the specific * datum types to be freely cast to this type. * * The values start at 1 - 0 is never a valid value. */ typedef struct symtab_datum { uint32_t value; } symtab_datum_t; typedef struct { hashtab_t table; /* hash table (keyed on a string) */ uint32_t nprim; /* number of primary names in table */ } symtab_t; extern int symtab_init(symtab_t *, unsigned int size); extern void symtab_destroy(symtab_t *); #endif /* _SYMTAB_H_ */ /* FLASK */ libsepol-2.2/include/sepol/policydb/util.h000066400000000000000000000022431223423440700206700ustar00rootroot00000000000000/* Authors: Karl MacMillan * * A set of utility functions that aid policy decision when dealing * with hierarchal namespaces. * * 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 */ #ifndef __SEPOL_UTIL_H__ #define __SEPOL_UTIL_H__ extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a); extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass, sepol_access_vector_t av); #endif libsepol-2.2/include/sepol/port_record.h000066400000000000000000000035441223423440700204350ustar00rootroot00000000000000#ifndef _SEPOL_PORT_RECORD_H_ #define _SEPOL_PORT_RECORD_H_ #include #include struct sepol_port; struct sepol_port_key; typedef struct sepol_port sepol_port_t; typedef struct sepol_port_key sepol_port_key_t; #define SEPOL_PROTO_UDP 0 #define SEPOL_PROTO_TCP 1 /* Key */ extern int sepol_port_compare(const sepol_port_t * port, const sepol_port_key_t * key); extern int sepol_port_compare2(const sepol_port_t * port, const sepol_port_t * port2); extern int sepol_port_key_create(sepol_handle_t * handle, int low, int high, int proto, sepol_port_key_t ** key_ptr); extern void sepol_port_key_unpack(const sepol_port_key_t * key, int *low, int *high, int *proto); extern int sepol_port_key_extract(sepol_handle_t * handle, const sepol_port_t * port, sepol_port_key_t ** key_ptr); extern void sepol_port_key_free(sepol_port_key_t * key); /* Protocol */ extern int sepol_port_get_proto(const sepol_port_t * port); extern void sepol_port_set_proto(sepol_port_t * port, int proto); extern const char *sepol_port_get_proto_str(int proto); /* Port */ extern int sepol_port_get_low(const sepol_port_t * port); extern int sepol_port_get_high(const sepol_port_t * port); extern void sepol_port_set_port(sepol_port_t * port, int port_num); extern void sepol_port_set_range(sepol_port_t * port, int low, int high); /* Context */ extern sepol_context_t *sepol_port_get_con(const sepol_port_t * port); extern int sepol_port_set_con(sepol_handle_t * handle, sepol_port_t * port, sepol_context_t * con); /* Create/Clone/Destroy */ extern int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port_ptr); extern int sepol_port_clone(sepol_handle_t * handle, const sepol_port_t * port, sepol_port_t ** port_ptr); extern void sepol_port_free(sepol_port_t * port); #endif libsepol-2.2/include/sepol/ports.h000066400000000000000000000023331223423440700172550ustar00rootroot00000000000000#ifndef _SEPOL_PORTS_H_ #define _SEPOL_PORTS_H_ #include #include #include /* Return the number of ports */ extern int sepol_port_count(sepol_handle_t * handle, const sepol_policydb_t * p, unsigned int *response); /* Check if a port exists */ extern int sepol_port_exists(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_port_key_t * key, int *response); /* Query a port - returns the port, or NULL if not found */ extern int sepol_port_query(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_port_key_t * key, sepol_port_t ** response); /* Modify a port, or add it, if the key is not found */ extern int sepol_port_modify(sepol_handle_t * handle, sepol_policydb_t * policydb, const sepol_port_key_t * key, const sepol_port_t * data); /* Iterate the ports * The handler may return: * -1 to signal an error condition, * 1 to signal successful exit * 0 to signal continue */ extern int sepol_port_iterate(sepol_handle_t * handle, const sepol_policydb_t * policydb, int (*fn) (const sepol_port_t * port, void *fn_arg), void *arg); #endif libsepol-2.2/include/sepol/roles.h000066400000000000000000000004161223423440700172320ustar00rootroot00000000000000#ifndef _SEPOL_ROLES_H_ #define _SEPOL_ROLES_H_ extern int sepol_role_exists(const sepol_policydb_t * policydb, const char *role, int *response); extern int sepol_role_list(const sepol_policydb_t * policydb, char ***roles, unsigned int *nroles); #endif libsepol-2.2/include/sepol/sepol.h000066400000000000000000000012331223423440700172260ustar00rootroot00000000000000#ifndef _SEPOL_H_ #define _SEPOL_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Set internal policydb from a file for subsequent service calls. */ extern int sepol_set_policydb_from_file(FILE * fp); #endif libsepol-2.2/include/sepol/user_record.h000066400000000000000000000044131223423440700204230ustar00rootroot00000000000000#ifndef _SEPOL_USER_RECORD_H_ #define _SEPOL_USER_RECORD_H_ #include #include struct sepol_user; struct sepol_user_key; typedef struct sepol_user sepol_user_t; typedef struct sepol_user_key sepol_user_key_t; /* Key */ extern int sepol_user_key_create(sepol_handle_t * handle, const char *name, sepol_user_key_t ** key); extern void sepol_user_key_unpack(const sepol_user_key_t * key, const char **name); extern int sepol_user_key_extract(sepol_handle_t * handle, const sepol_user_t * user, sepol_user_key_t ** key_ptr); extern void sepol_user_key_free(sepol_user_key_t * key); extern int sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key); extern int sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2); /* Name */ extern const char *sepol_user_get_name(const sepol_user_t * user); extern int sepol_user_set_name(sepol_handle_t * handle, sepol_user_t * user, const char *name); /* MLS */ extern const char *sepol_user_get_mlslevel(const sepol_user_t * user); extern int sepol_user_set_mlslevel(sepol_handle_t * handle, sepol_user_t * user, const char *mls_level); extern const char *sepol_user_get_mlsrange(const sepol_user_t * user); extern int sepol_user_set_mlsrange(sepol_handle_t * handle, sepol_user_t * user, const char *mls_range); /* Role management */ extern int sepol_user_get_num_roles(const sepol_user_t * user); extern int sepol_user_add_role(sepol_handle_t * handle, sepol_user_t * user, const char *role); extern void sepol_user_del_role(sepol_user_t * user, const char *role); extern int sepol_user_has_role(const sepol_user_t * user, const char *role); extern int sepol_user_get_roles(sepol_handle_t * handle, const sepol_user_t * user, const char ***roles_arr, unsigned int *num_roles); extern int sepol_user_set_roles(sepol_handle_t * handle, sepol_user_t * user, const char **roles_arr, unsigned int num_roles); /* Create/Clone/Destroy */ extern int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr); extern int sepol_user_clone(sepol_handle_t * handle, const sepol_user_t * user, sepol_user_t ** user_ptr); extern void sepol_user_free(sepol_user_t * user); #endif libsepol-2.2/include/sepol/users.h000066400000000000000000000036421223423440700172530ustar00rootroot00000000000000#ifndef _SEPOL_USERS_H_ #define _SEPOL_USERS_H_ #include #include #include #include /*---------compatibility------------*/ /* Given an existing binary policy (starting at 'data with length 'len') and user configurations living in 'usersdir', generate a new binary policy for the new user configurations. Sets '*newdata' and '*newlen' to refer to the new binary policy image. */ extern int sepol_genusers(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen); /* Enable or disable deletion of users by sepol_genusers(3) when a user in original binary policy image is not defined by the new user configurations. Defaults to disabled. */ extern void sepol_set_delusers(int on); /*--------end compatibility----------*/ /* Modify the user, or add it, if the key is not found */ extern int sepol_user_modify(sepol_handle_t * handle, sepol_policydb_t * policydb, const sepol_user_key_t * key, const sepol_user_t * data); /* Return the number of users */ extern int sepol_user_count(sepol_handle_t * handle, const sepol_policydb_t * p, unsigned int *response); /* Check if the specified user exists */ extern int sepol_user_exists(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_user_key_t * key, int *response); /* Query a user - returns the user or NULL if not found */ extern int sepol_user_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_user_key_t * key, sepol_user_t ** response); /* Iterate the users * The handler may return: * -1 to signal an error condition, * 1 to signal successful exit * 0 to signal continue */ extern int sepol_user_iterate(sepol_handle_t * handle, const sepol_policydb_t * policydb, int (*fn) (const sepol_user_t * user, void *fn_arg), void *arg); #endif libsepol-2.2/man/000077500000000000000000000000001223423440700137425ustar00rootroot00000000000000libsepol-2.2/man/Makefile000066400000000000000000000003651223423440700154060ustar00rootroot00000000000000# Installation directories. MAN8DIR ?= $(DESTDIR)/usr/share/man/man8 MAN3DIR ?= $(DESTDIR)/usr/share/man/man3 all: install: all mkdir -p $(MAN3DIR) mkdir -p $(MAN8DIR) install -m 644 man3/*.3 $(MAN3DIR) install -m 644 man8/*.8 $(MAN8DIR) libsepol-2.2/man/man3/000077500000000000000000000000001223423440700146005ustar00rootroot00000000000000libsepol-2.2/man/man3/sepol_check_context.3000066400000000000000000000015411223423440700207100ustar00rootroot00000000000000.TH "sepol_check_context" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation" .SH "NAME" sepol_check_context \- Check the validity of a security context against a binary policy. .SH "SYNOPSIS" .B #include .sp .BI "int sepol_check_context(const char *" context ");" .sp .BI "int sepol_set_policydb_from_file(FILE *" fp ");" .SH "DESCRIPTION" .B sepol_check_context checks the validity of a security context against a binary policy previously loaded from a file via .B sepol_set_policydb_from_file. It is used by .B setfiles -c to validate a file contexts configuration against the binary policy upon policy builds. For validating a context against the active policy on a SELinux system, use .B security_check_context from libselinux instead. .SH "RETURN VALUE" Returns 0 on success or \-1 with errno set otherwise. libsepol-2.2/man/man3/sepol_genbools.3000066400000000000000000000024501223423440700176770ustar00rootroot00000000000000.TH "sepol_genbools" "3" "11 August 2004" "sds@epoch.ncsc.mil" "SE Linux binary policy API documentation" .SH "NAME" sepol_genbools \- Rewrite a binary policy with different boolean settings .SH "SYNOPSIS" .B #include .sp .BI "int sepol_genbools(void *" data ", size_t "len ", char *" boolpath ); .br .BI "int sepol_genbools_array(void *" data ", size_t " len ", char **" names ", int *" values ", int " nel ); .SH "DESCRIPTION" .B sepol_genbools rewrites a binary policy stored in the memory region described by (data, len) to use the boolean settings specified in the file named by boolpath. The boolean settings are specified by name=value lines where value may be 0 or false to disable or 1 or true to enable. The binary policy is rewritten in place in memory. .B sepol_genbools_array does likewise, but obtains the boolean settings from the parallel arrays (names, values) with nel elements each. .SH "RETURN VALUE" Returns 0 on success or \-1 otherwise, with errno set appropriately. An errno of ENOENT indicates that the boolean file did not exist. An errno of EINVAL indicates that one or more booleans listed in the boolean file was undefined in the policy or had an invalid value specified; in this case, the binary policy is still rewritten but any invalid boolean settings are ignored. libsepol-2.2/man/man3/sepol_genusers.3000066400000000000000000000035651223423440700177320ustar00rootroot00000000000000.TH "sepol_genusers" "3" "15 March 2005" "sds@tycho.nsa.gov" "SE Linux binary policy API documentation" .SH "NAME" sepol_genusers \- Generate a new binary policy image with a customized user configuration .SH "SYNOPSIS" .B #include .sp .BI "int sepol_genusers(void *" data ", size_t "len ", const char *" usersdir ", void *" newdata ", size_t *" newlen); .sp .BI "void sepol_set_delusers(int " on ");" .SH "DESCRIPTION" .B sepol_genusers generates a new binary policy image from an existing binary policy image stored in the memory region described by the starting address .I data and the length .I len and a pair of user configuration files named .B system.users and .B local.users from the directory specified by .I usersdir. The resulting binary policy is placed into dynamically allocated memory and the variables .I newdata and .I newlen are set to refer to the new binary image's starting address and length. The original binary policy image is not modified. By default, .B sepol_genusers will preserve user entries that are defined in the original binary policy image but not defined in the user configuration files. If such user entries should instead by omitted entirely from the new binary policy image, then the .B sepol_set_delusers function may be called with .I on set to 1 prior to calling .B sepol_genusers in order to enable deletion of such users. .SH "RETURN VALUE" Returns 0 on success or \-1 otherwise, with errno set appropriately. An errno of ENOENT indicates that one or both of the user configuration files did not exist. An errno of EINVAL indicates that either the original binary policy image or the generated one were invalid. An errno of ENOMEM indicates that insufficient memory was available to process the original binary policy image or to generate the new policy image. Invalid entries in the user configuration files are skipped with a warning. libsepol-2.2/man/man8/000077500000000000000000000000001223423440700146055ustar00rootroot00000000000000libsepol-2.2/man/man8/chkcon.8000066400000000000000000000031601223423440700161430ustar00rootroot00000000000000.\" Hey, Emacs! This is an -*- nroff -*- source file. .\" Copyright (c) 1997 Manoj Srivastava .\" .\" This is free documentation; 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. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual 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 manual; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, .\" USA. .\" .TH CHKCON 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation" .SH NAME chkcon \- determine if a security context is valid for a given binary policy .SH SYNOPSIS chkcon policy_file context .SH DESCRIPTION This utility validates (the string representation of) a security context specified by the argument .I context against configuration data read in from a policy database binary representation file specified by the argument .I policy_file. .SH FILES policy file .SH AUTHOR This manual page (and just the manual page) was written by Manoj Srivastava . libsepol-2.2/man/man8/genpolbools.8000066400000000000000000000010351223423440700172200ustar00rootroot00000000000000.TH "genpolbools" "8" "11 August 2004" "sds@epoch.ncsc.mil" "SELinux Command Line documentation" .SH "NAME" genpolbools \- Rewrite a binary policy with different boolean settings .SH "SYNOPSIS" .B genpolbools oldpolicy booleans newpolicy .SH "DESCRIPTION" .B genpolbools rewrites an existing binary policy with different boolean settings, generating a new binary policy. The booleans file specifies the different boolean settings using name=value lines, where value can be 0 or false to disable the boolean or 1 or true to enable it. libsepol-2.2/man/man8/genpolusers.8000066400000000000000000000031331223423440700172440ustar00rootroot00000000000000.\" Hey, Emacs! This is an -*- nroff -*- source file. .\" Copyright (c) 1997 Manoj Srivastava .\" .\" This is free documentation; 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. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual 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 manual; if not, write to the Free .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, .\" USA. .\" .TH GENPOLUSERS 8 "Mar 12 2005" "SELinux" "SELinux Command Line documentation" .SH NAME genpolusers \- Generate new binary policy with updated user configuration .SH SYNOPSIS genpolusers in-policy usersdir out-policy .SH DESCRIPTION Given an existing binary policy file .I in\-policy, generate a new binary policy .I out\-policy with an updated user configuration based on any .B system.users and .B local.users files in the specified .I usersdir. .SH AUTHOR This manual page (and just the manual page) was written by Manoj Srivastava . libsepol-2.2/src/000077500000000000000000000000001223423440700137565ustar00rootroot00000000000000libsepol-2.2/src/Makefile000066400000000000000000000030631223423440700154200ustar00rootroot00000000000000# Installation directories. PREFIX ?= $(DESTDIR)/usr INCLUDEDIR ?= $(PREFIX)/include LIBDIR ?= $(PREFIX)/lib SHLIBDIR ?= $(DESTDIR)/lib RANLIB ?= ranlib LIBBASE ?= $(shell basename $(LIBDIR)) VERSION = $(shell cat ../VERSION) LIBVERSION = 1 LIBA=libsepol.a TARGET=libsepol.so LIBPC=libsepol.pc LIBSO=$(TARGET).$(LIBVERSION) OBJS= $(patsubst %.c,%.o,$(wildcard *.c)) LOBJS= $(patsubst %.c,%.lo,$(wildcard *.c)) CFLAGS ?= -Werror -Wall -W -Wundef -Wshadow -Wmissing-noreturn -Wmissing-format-attribute override CFLAGS += -I. -I../include -D_GNU_SOURCE all: $(LIBA) $(LIBSO) $(LIBPC) $(LIBA): $(OBJS) $(AR) rcs $@ $^ $(RANLIB) $@ $(LIBSO): $(LOBJS) $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname,$(LIBSO),--version-script=libsepol.map,-z,defs ln -sf $@ $(TARGET) $(LIBPC): $(LIBPC).in ../VERSION sed -e 's/@VERSION@/$(VERSION)/; s:@prefix@:$(PREFIX):; s:@libdir@:$(LIBBASE):; s:@includedir@:$(INCLUDEDIR):' < $< > $@ %.o: %.c $(CC) $(CFLAGS) -fPIC -c -o $@ $< %.lo: %.c $(CC) $(CFLAGS) -fPIC -DSHARED -c -o $@ $< install: all test -d $(LIBDIR) || install -m 755 -d $(LIBDIR) install -m 644 $(LIBA) $(LIBDIR) test -d $(SHLIBDIR) || install -m 755 -d $(SHLIBDIR) install -m 755 $(LIBSO) $(SHLIBDIR) test -d $(LIBDIR)/pkgconfig || install -m 755 -d $(LIBDIR)/pkgconfig install -m 644 $(LIBPC) $(LIBDIR)/pkgconfig cd $(LIBDIR) && ln -sf ../../`basename $(SHLIBDIR)`/$(LIBSO) $(TARGET) relabel: /sbin/restorecon $(SHLIBDIR)/$(LIBSO) clean: -rm -f $(LIBPC) $(OBJS) $(LOBJS) $(LIBA) $(LIBSO) $(TARGET) indent: ../../scripts/Lindent $(wildcard *.[ch]) libsepol-2.2/src/assertion.c000066400000000000000000000103531223423440700161330ustar00rootroot00000000000000/* Authors: Joshua Brindle * * Assertion checker for avtab entries, taken from * checkpolicy.c by Stephen Smalley * * Copyright (C) 2005 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 #include #include #include #include "debug.h" static int check_assertion_helper(sepol_handle_t * handle, policydb_t * p, avtab_t * te_avtab, avtab_t * te_cond_avtab, unsigned int stype, unsigned int ttype, class_perm_node_t * perm, unsigned long line) { avtab_key_t avkey; avtab_ptr_t node; class_perm_node_t *curperm; for (curperm = perm; curperm != NULL; curperm = curperm->next) { avkey.source_type = stype + 1; avkey.target_type = ttype + 1; avkey.target_class = curperm->class; avkey.specified = AVTAB_ALLOWED; for (node = avtab_search_node(te_avtab, &avkey); node != NULL; node = avtab_search_node_next(node, avkey.specified)) { if (node->datum.data & curperm->data) goto err; } for (node = avtab_search_node(te_cond_avtab, &avkey); node != NULL; node = avtab_search_node_next(node, avkey.specified)) { if (node->datum.data & curperm->data) goto err; } } return 0; err: if (line) { ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };", line, p->p_type_val_to_name[stype], p->p_type_val_to_name[ttype], p->p_class_val_to_name[curperm->class - 1], sepol_av_to_string(p, curperm->class, node->datum.data & curperm->data)); } else { ERR(handle, "neverallow violated by allow %s %s:%s {%s };", p->p_type_val_to_name[stype], p->p_type_val_to_name[ttype], p->p_class_val_to_name[curperm->class - 1], sepol_av_to_string(p, curperm->class, node->datum.data & curperm->data)); } return -1; } int check_assertions(sepol_handle_t * handle, policydb_t * p, avrule_t * avrules) { avrule_t *a; avtab_t te_avtab, te_cond_avtab; ebitmap_node_t *snode, *tnode; unsigned int i, j; int rc; if (!avrules) { /* Since assertions are stored in avrules, if it is NULL there won't be any to check. This also prevents an invalid free if the avtabs are never initialized */ return 0; } if (avrules) { if (avtab_init(&te_avtab)) goto oom; if (avtab_init(&te_cond_avtab)) { avtab_destroy(&te_avtab); goto oom; } if (expand_avtab(p, &p->te_avtab, &te_avtab) || expand_avtab(p, &p->te_cond_avtab, &te_cond_avtab)) { avtab_destroy(&te_avtab); avtab_destroy(&te_cond_avtab); goto oom; } } for (a = avrules; a != NULL; a = a->next) { ebitmap_t *stypes = &a->stypes.types; ebitmap_t *ttypes = &a->ttypes.types; if (!(a->specified & AVRULE_NEVERALLOW)) continue; ebitmap_for_each_bit(stypes, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; if (a->flags & RULE_SELF) { if (check_assertion_helper (handle, p, &te_avtab, &te_cond_avtab, i, i, a->perms, a->line)) { rc = -1; goto out; } } ebitmap_for_each_bit(ttypes, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; if (check_assertion_helper (handle, p, &te_avtab, &te_cond_avtab, i, j, a->perms, a->line)) { rc = -1; goto out; } } } } rc = 0; out: avtab_destroy(&te_avtab); avtab_destroy(&te_cond_avtab); return rc; oom: ERR(handle, "Out of memory - unable to check neverallows"); return -1; } libsepol-2.2/src/av_permissions.h000066400000000000000000000002411223423440700171650ustar00rootroot00000000000000/* Used by security_compute_av. */ #define PROCESS__TRANSITION 0x00000002UL #define PROCESS__DYNTRANSITION 0x00800000UL libsepol-2.2/src/avrule_block.c000066400000000000000000000123271223423440700165770ustar00rootroot00000000000000/* Authors: Jason Tang * * Functions that manipulate a logical block (conditional, optional, * or global scope) for a policy module. * * Copyright (C) 2005 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 #include #include #include #include /* It is anticipated that there be less declarations within an avrule * block than the global policy. Thus the symbol table sizes are * smaller than those listed in policydb.c */ static unsigned int symtab_sizes[SYM_NUM] = { 2, 4, 8, 32, 16, 4, 2, 2, }; avrule_block_t *avrule_block_create(void) { avrule_block_t *block; if ((block = calloc(1, sizeof(*block))) == NULL) { return NULL; } return block; } avrule_decl_t *avrule_decl_create(uint32_t decl_id) { avrule_decl_t *decl; int i; if ((decl = calloc(1, sizeof(*decl))) == NULL) { return NULL; } decl->decl_id = decl_id; for (i = 0; i < SYM_NUM; i++) { if (symtab_init(&decl->symtab[i], symtab_sizes[i])) { avrule_decl_destroy(decl); return NULL; } } for (i = 0; i < SYM_NUM; i++) { ebitmap_init(&decl->required.scope[i]); ebitmap_init(&decl->declared.scope[i]); } return decl; } /* note that unlike the other destroy functions, this one does /NOT/ * destroy the pointer itself */ static void scope_index_destroy(scope_index_t * scope) { unsigned int i; if (scope == NULL) { return; } for (i = 0; i < SYM_NUM; i++) { ebitmap_destroy(scope->scope + i); } for (i = 0; i < scope->class_perms_len; i++) { ebitmap_destroy(scope->class_perms_map + i); } free(scope->class_perms_map); } void avrule_decl_destroy(avrule_decl_t * x) { if (x == NULL) { return; } cond_list_destroy(x->cond_list); avrule_list_destroy(x->avrules); role_trans_rule_list_destroy(x->role_tr_rules); filename_trans_rule_list_destroy(x->filename_trans_rules); role_allow_rule_list_destroy(x->role_allow_rules); range_trans_rule_list_destroy(x->range_tr_rules); scope_index_destroy(&x->required); scope_index_destroy(&x->declared); symtabs_destroy(x->symtab); free(x->module_name); free(x); } void avrule_block_destroy(avrule_block_t * x) { avrule_decl_t *decl; if (x == NULL) { return; } decl = x->branch_list; while (decl != NULL) { avrule_decl_t *next_decl = decl->next; avrule_decl_destroy(decl); decl = next_decl; } free(x); } void avrule_block_list_destroy(avrule_block_t * x) { while (x != NULL) { avrule_block_t *next = x->next; avrule_block_destroy(x); x = next; } } /* Get a conditional node from a avrule_decl with the same expression. * If that expression does not exist then create one. */ cond_list_t *get_decl_cond_list(policydb_t * p, avrule_decl_t * decl, cond_list_t * cond) { cond_list_t *result; int was_created; result = cond_node_find(p, cond, decl->cond_list, &was_created); if (result != NULL && was_created) { result->next = decl->cond_list; decl->cond_list = result; } return result; } /* Look up an identifier in a policy's scoping table. If it is there, * marked as SCOPE_DECL, and any of its declaring block has been enabled, * then return 1. Otherwise return 0. Can only be called after the * decl_val_to_struct index has been created */ int is_id_enabled(char *id, policydb_t * p, int symbol_table) { scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symbol_table].table, id); uint32_t i; if (scope == NULL) { return 0; } if (scope->scope != SCOPE_DECL) { return 0; } for (i = 0; i < scope->decl_ids_len; i++) { avrule_decl_t *decl = p->decl_val_to_struct[scope->decl_ids[i] - 1]; if (decl != NULL && decl->enabled) { return 1; } } return 0; } /* Check if a particular permission is present within the given class, * and that the class is enabled. Returns 1 if both conditions are * true, 0 if neither could be found or if the class id disabled. */ int is_perm_enabled(char *class_id, char *perm_id, policydb_t * p) { class_datum_t *cladatum; perm_datum_t *perm; if (!is_id_enabled(class_id, p, SYM_CLASSES)) { return 0; } cladatum = (class_datum_t *) hashtab_search(p->p_classes.table, class_id); if (cladatum == NULL) { return 0; } perm = hashtab_search(cladatum->permissions.table, perm_id); if (perm == NULL && cladatum->comdatum != 0) { /* permission was not in this class. before giving * up, check the class's parent */ perm = hashtab_search(cladatum->comdatum->permissions.table, perm_id); } if (perm == NULL) { return 0; } return 1; } libsepol-2.2/src/avtab.c000066400000000000000000000311611223423440700152210ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Yuichi Nakamura * Tuned number of hash slots for avtab to reduce memory usage */ /* Updated: Frank Mayer * and Karl MacMillan * * Added conditional policy language extensions * * Updated: Red Hat, Inc. James Morris * * Code cleanup * * Updated: Karl MacMillan * * Copyright (C) 2003 Tresys Technology, LLC * Copyright (C) 2003,2007 Red Hat, Inc. * * 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 */ /* FLASK */ /* * Implementation of the access vector table type. */ #include #include #include #include #include "debug.h" #include "private.h" static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask) { return ((keyp->target_class + (keyp->target_type << 2) + (keyp->source_type << 9)) & mask); } static avtab_ptr_t avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, avtab_datum_t * datum) { avtab_ptr_t newnode; newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node)); if (newnode == NULL) return NULL; memset(newnode, 0, sizeof(struct avtab_node)); newnode->key = *key; newnode->datum = *datum; if (prev) { newnode->next = prev->next; prev->next = newnode; } else { newnode->next = h->htable[hvalue]; h->htable[hvalue] = newnode; } h->nel++; return newnode; } int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) { int hvalue; avtab_ptr_t prev, cur, newnode; uint16_t specified = key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); if (!h || !h->htable) return SEPOL_ENOMEM; hvalue = avtab_hash(key, h->mask); for (prev = NULL, cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) return SEPOL_EEXIST; if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && key->target_type < cur->key.target_type) break; if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class < cur->key.target_class) break; } newnode = avtab_insert_node(h, hvalue, prev, key, datum); if (!newnode) return SEPOL_ENOMEM; return 0; } /* Unlike avtab_insert(), this function allow multiple insertions of the same * key/specified mask into the table, as needed by the conditional avtab. * It also returns a pointer to the node inserted. */ avtab_ptr_t avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) { int hvalue; avtab_ptr_t prev, cur, newnode; uint16_t specified = key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); if (!h || !h->htable) return NULL; hvalue = avtab_hash(key, h->mask); for (prev = NULL, cur = h->htable[hvalue]; cur; prev = cur, cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) break; if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && key->target_type < cur->key.target_type) break; if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class < cur->key.target_class) break; } newnode = avtab_insert_node(h, hvalue, prev, key, datum); return newnode; } avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key) { int hvalue; avtab_ptr_t cur; uint16_t specified = key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); if (!h || !h->htable) return NULL; hvalue = avtab_hash(key, h->mask); for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) return &cur->datum; if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && key->target_type < cur->key.target_type) break; if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class < cur->key.target_class) break; } return NULL; } /* This search function returns a node pointer, and can be used in * conjunction with avtab_search_next_node() */ avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key) { int hvalue; avtab_ptr_t cur; uint16_t specified = key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); if (!h || !h->htable) return NULL; hvalue = avtab_hash(key, h->mask); for (cur = h->htable[hvalue]; cur; cur = cur->next) { if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && (specified & cur->key.specified)) return cur; if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && key->target_type < cur->key.target_type) break; if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class < cur->key.target_class) break; } return NULL; } avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified) { avtab_ptr_t cur; if (!node) return NULL; specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); for (cur = node->next; cur; cur = cur->next) { if (node->key.source_type == cur->key.source_type && node->key.target_type == cur->key.target_type && node->key.target_class == cur->key.target_class && (specified & cur->key.specified)) return cur; if (node->key.source_type < cur->key.source_type) break; if (node->key.source_type == cur->key.source_type && node->key.target_type < cur->key.target_type) break; if (node->key.source_type == cur->key.source_type && node->key.target_type == cur->key.target_type && node->key.target_class < cur->key.target_class) break; } return NULL; } void avtab_destroy(avtab_t * h) { unsigned int i; avtab_ptr_t cur, temp; if (!h || !h->htable) return; for (i = 0; i < h->nslot; i++) { cur = h->htable[i]; while (cur != NULL) { temp = cur; cur = cur->next; free(temp); } h->htable[i] = NULL; } free(h->htable); h->htable = NULL; h->nslot = 0; h->mask = 0; } int avtab_map(avtab_t * h, int (*apply) (avtab_key_t * k, avtab_datum_t * d, void *args), void *args) { unsigned int i; int ret; avtab_ptr_t cur; if (!h) return 0; for (i = 0; i < h->nslot; i++) { cur = h->htable[i]; while (cur != NULL) { ret = apply(&cur->key, &cur->datum, args); if (ret) return ret; cur = cur->next; } } return 0; } int avtab_init(avtab_t * h) { h->htable = NULL; h->nel = 0; return 0; } int avtab_alloc(avtab_t *h, uint32_t nrules) { uint16_t mask = 0; uint32_t shift = 0; uint32_t work = nrules; uint32_t nslot = 0; if (nrules == 0) goto out; while (work) { work = work >> 1; shift++; } if (shift > 2) shift = shift - 2; nslot = 1 << shift; if (nslot > MAX_AVTAB_SIZE) nslot = MAX_AVTAB_SIZE; mask = nslot - 1; h->htable = calloc(nslot, sizeof(avtab_ptr_t)); if (!h->htable) return -1; out: h->nel = 0; h->nslot = nslot; h->mask = mask; return 0; } void avtab_hash_eval(avtab_t * h, char *tag) { unsigned int i, chain_len, slots_used, max_chain_len; avtab_ptr_t cur; slots_used = 0; max_chain_len = 0; for (i = 0; i < h->nslot; i++) { cur = h->htable[i]; if (cur) { slots_used++; chain_len = 0; while (cur) { chain_len++; cur = cur->next; } if (chain_len > max_chain_len) max_chain_len = chain_len; } } printf ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", tag, h->nel, slots_used, h->nslot, max_chain_len); } /* Ordering of datums in the original avtab format in the policy file. */ static uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, AVTAB_MEMBER }; int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, int (*insertf) (avtab_t * a, avtab_key_t * k, avtab_datum_t * d, void *p), void *p) { uint16_t buf16[4], enabled; uint32_t buf32[7], items, items2, val; avtab_key_t key; avtab_datum_t datum; unsigned set; unsigned int i; int rc; memset(&key, 0, sizeof(avtab_key_t)); memset(&datum, 0, sizeof(avtab_datum_t)); if (vers < POLICYDB_VERSION_AVTAB) { rc = next_entry(buf32, fp, sizeof(uint32_t)); if (rc < 0) { ERR(fp->handle, "truncated entry"); return -1; } items2 = le32_to_cpu(buf32[0]); if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) { ERR(fp->handle, "invalid item count"); return -1; } rc = next_entry(buf32, fp, sizeof(uint32_t) * items2); if (rc < 0) { ERR(fp->handle, "truncated entry"); return -1; } items = 0; val = le32_to_cpu(buf32[items++]); key.source_type = (uint16_t) val; if (key.source_type != val) { ERR(fp->handle, "truncated source type"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_type = (uint16_t) val; if (key.target_type != val) { ERR(fp->handle, "truncated target type"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_class = (uint16_t) val; if (key.target_class != val) { ERR(fp->handle, "truncated target class"); return -1; } val = le32_to_cpu(buf32[items++]); enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; if (!(val & (AVTAB_AV | AVTAB_TYPE))) { ERR(fp->handle, "null entry"); return -1; } if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { ERR(fp->handle, "entry has both access " "vectors and types"); return -1; } for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { key.specified = spec_order[i] | enabled; datum.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); if (rc) return rc; } } if (items != items2) { ERR(fp->handle, "entry only had %d items, " "expected %d", items2, items); return -1; } return 0; } rc = next_entry(buf16, fp, sizeof(uint16_t) * 4); if (rc < 0) { ERR(fp->handle, "truncated entry"); return -1; } items = 0; key.source_type = le16_to_cpu(buf16[items++]); key.target_type = le16_to_cpu(buf16[items++]); key.target_class = le16_to_cpu(buf16[items++]); key.specified = le16_to_cpu(buf16[items++]); set = 0; for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (key.specified & spec_order[i]) set++; } if (!set || set > 1) { ERR(fp->handle, "more than one specifier"); return -1; } rc = next_entry(buf32, fp, sizeof(uint32_t)); if (rc < 0) { ERR(fp->handle, "truncated entry"); return -1; } datum.data = le32_to_cpu(*buf32); return insertf(a, &key, &datum, p); } static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d, void *p __attribute__ ((unused))) { return avtab_insert(a, k, d); } int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers) { unsigned int i; int rc; uint32_t buf[1]; uint32_t nel; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { ERR(fp->handle, "truncated table"); goto bad; } nel = le32_to_cpu(buf[0]); if (!nel) { ERR(fp->handle, "table is empty"); goto bad; } rc = avtab_alloc(a, nel); if (rc) { ERR(fp->handle, "out of memory"); goto bad; } for (i = 0; i < nel; i++) { rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL); if (rc) { if (rc == SEPOL_ENOMEM) ERR(fp->handle, "out of memory"); if (rc == SEPOL_EEXIST) ERR(fp->handle, "duplicate entry"); ERR(fp->handle, "failed on entry %d of %u", i, nel); goto bad; } } return 0; bad: avtab_destroy(a); return -1; } libsepol-2.2/src/boolean_internal.h000066400000000000000000000007121223423440700174420ustar00rootroot00000000000000#ifndef _SEPOL_BOOLEAN_INTERNAL_H_ #define _SEPOL_BOOLEAN_INTERNAL_H_ #include #include #include "dso.h" hidden_proto(sepol_bool_key_create) hidden_proto(sepol_bool_key_unpack) hidden_proto(sepol_bool_get_name) hidden_proto(sepol_bool_set_name) hidden_proto(sepol_bool_get_value) hidden_proto(sepol_bool_set_value) hidden_proto(sepol_bool_create) hidden_proto(sepol_bool_free) #endif libsepol-2.2/src/boolean_record.c000066400000000000000000000063271223423440700171070ustar00rootroot00000000000000#include #include #include #include "boolean_internal.h" #include "debug.h" struct sepol_bool { /* This boolean's name */ char *name; /* Its value */ int value; }; struct sepol_bool_key { /* This boolean's name */ const char *name; }; int sepol_bool_key_create(sepol_handle_t * handle, const char *name, sepol_bool_key_t ** key_ptr) { sepol_bool_key_t *tmp_key = (sepol_bool_key_t *) malloc(sizeof(struct sepol_bool_key)); if (!tmp_key) { ERR(handle, "out of memory, " "could not create boolean key"); return STATUS_ERR; } tmp_key->name = name; *key_ptr = tmp_key; return STATUS_SUCCESS; } hidden_def(sepol_bool_key_create) void sepol_bool_key_unpack(const sepol_bool_key_t * key, const char **name) { *name = key->name; } hidden_def(sepol_bool_key_unpack) int sepol_bool_key_extract(sepol_handle_t * handle, const sepol_bool_t * boolean, sepol_bool_key_t ** key_ptr) { if (sepol_bool_key_create(handle, boolean->name, key_ptr) < 0) { ERR(handle, "could not extract key from boolean %s", boolean->name); return STATUS_ERR; } return STATUS_SUCCESS; } void sepol_bool_key_free(sepol_bool_key_t * key) { free(key); } int sepol_bool_compare(const sepol_bool_t * boolean, const sepol_bool_key_t * key) { return strcmp(boolean->name, key->name); } int sepol_bool_compare2(const sepol_bool_t * boolean, const sepol_bool_t * boolean2) { return strcmp(boolean->name, boolean2->name); } /* Name */ const char *sepol_bool_get_name(const sepol_bool_t * boolean) { return boolean->name; } hidden_def(sepol_bool_get_name) int sepol_bool_set_name(sepol_handle_t * handle, sepol_bool_t * boolean, const char *name) { char *tmp_name = strdup(name); if (!tmp_name) { ERR(handle, "out of memory, could not set boolean name"); return STATUS_ERR; } free(boolean->name); boolean->name = tmp_name; return STATUS_SUCCESS; } hidden_def(sepol_bool_set_name) /* Value */ int sepol_bool_get_value(const sepol_bool_t * boolean) { return boolean->value; } hidden_def(sepol_bool_get_value) void sepol_bool_set_value(sepol_bool_t * boolean, int value) { boolean->value = value; } hidden_def(sepol_bool_set_value) /* Create */ int sepol_bool_create(sepol_handle_t * handle, sepol_bool_t ** bool_ptr) { sepol_bool_t *boolean = (sepol_bool_t *) malloc(sizeof(sepol_bool_t)); if (!boolean) { ERR(handle, "out of memory, " "could not create boolean record"); return STATUS_ERR; } boolean->name = NULL; boolean->value = 0; *bool_ptr = boolean; return STATUS_SUCCESS; } hidden_def(sepol_bool_create) /* Deep copy clone */ int sepol_bool_clone(sepol_handle_t * handle, const sepol_bool_t * boolean, sepol_bool_t ** bool_ptr) { sepol_bool_t *new_bool = NULL; if (sepol_bool_create(handle, &new_bool) < 0) goto err; if (sepol_bool_set_name(handle, new_bool, boolean->name) < 0) goto err; new_bool->value = boolean->value; *bool_ptr = new_bool; return STATUS_SUCCESS; err: ERR(handle, "could not clone boolean record"); sepol_bool_free(new_bool); return STATUS_ERR; } /* Destroy */ void sepol_bool_free(sepol_bool_t * boolean) { if (!boolean) return; free(boolean->name); free(boolean); } hidden_def(sepol_bool_free) libsepol-2.2/src/booleans.c000066400000000000000000000107031223423440700157250ustar00rootroot00000000000000#include #include #include "handle.h" #include "private.h" #include "debug.h" #include #include #include #include #include "boolean_internal.h" static int bool_update(sepol_handle_t * handle, policydb_t * policydb, const sepol_bool_key_t * key, const sepol_bool_t * data) { const char *cname; char *name; int value; sepol_bool_key_unpack(key, &cname); name = strdup(cname); value = sepol_bool_get_value(data); if (!name) goto omem; cond_bool_datum_t *datum = hashtab_search(policydb->p_bools.table, name); if (!datum) { ERR(handle, "boolean %s no longer in policy", name); goto err; } if (value != 0 && value != 1) { ERR(handle, "illegal value %d for boolean %s", value, name); goto err; } free(name); datum->state = value; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: free(name); ERR(handle, "could not update boolean %s", cname); return STATUS_ERR; } static int bool_to_record(sepol_handle_t * handle, const policydb_t * policydb, int bool_idx, sepol_bool_t ** record) { const char *name = policydb->p_bool_val_to_name[bool_idx]; cond_bool_datum_t *booldatum = policydb->bool_val_to_struct[bool_idx]; int value = booldatum->state; sepol_bool_t *tmp_record = NULL; if (sepol_bool_create(handle, &tmp_record) < 0) goto err; if (sepol_bool_set_name(handle, tmp_record, name) < 0) goto err; sepol_bool_set_value(tmp_record, value); *record = tmp_record; return STATUS_SUCCESS; err: ERR(handle, "could not convert boolean %s to record", name); sepol_bool_free(tmp_record); return STATUS_ERR; } int sepol_bool_set(sepol_handle_t * handle, sepol_policydb_t * p, const sepol_bool_key_t * key, const sepol_bool_t * data) { const char *name; sepol_bool_key_unpack(key, &name); policydb_t *policydb = &p->p; if (bool_update(handle, policydb, key, data) < 0) goto err; if (evaluate_conds(policydb) < 0) { ERR(handle, "error while re-evaluating conditionals"); goto err; } return STATUS_SUCCESS; err: ERR(handle, "could not set boolean %s", name); return STATUS_ERR; } int sepol_bool_count(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, unsigned int *response) { const policydb_t *policydb = &p->p; *response = policydb->p_bools.nprim; handle = NULL; return STATUS_SUCCESS; } int sepol_bool_exists(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_bool_key_t * key, int *response) { const policydb_t *policydb = &p->p; const char *cname; char *name = NULL; sepol_bool_key_unpack(key, &cname); name = strdup(cname); if (!name) { ERR(handle, "out of memory, could not check " "if user %s exists", cname); return STATUS_ERR; } *response = (hashtab_search(policydb->p_bools.table, name) != NULL); free(name); return STATUS_SUCCESS; } int sepol_bool_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_bool_key_t * key, sepol_bool_t ** response) { const policydb_t *policydb = &p->p; cond_bool_datum_t *booldatum = NULL; const char *cname; char *name = NULL; sepol_bool_key_unpack(key, &cname); name = strdup(cname); if (!name) goto omem; booldatum = hashtab_search(policydb->p_bools.table, name); if (!booldatum) { *response = NULL; return STATUS_SUCCESS; } if (bool_to_record(handle, policydb, booldatum->s.value - 1, response) < 0) goto err; free(name); return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not query boolean %s", cname); free(name); return STATUS_ERR; } int sepol_bool_iterate(sepol_handle_t * handle, const sepol_policydb_t * p, int (*fn) (const sepol_bool_t * boolean, void *fn_arg), void *arg) { const policydb_t *policydb = &p->p; unsigned int nbools = policydb->p_bools.nprim; sepol_bool_t *boolean = NULL; unsigned int i; /* For each boolean */ for (i = 0; i < nbools; i++) { int status; if (bool_to_record(handle, policydb, i, &boolean) < 0) goto err; /* Invoke handler */ status = fn(boolean, arg); if (status < 0) goto err; sepol_bool_free(boolean); boolean = NULL; /* Handler requested exit */ if (status > 0) break; } return STATUS_SUCCESS; err: ERR(handle, "could not iterate over booleans"); sepol_bool_free(boolean); return STATUS_ERR; } libsepol-2.2/src/conditional.c000066400000000000000000000506311223423440700164320ustar00rootroot00000000000000/* Authors: Karl MacMillan * Frank Mayer * David Caplan * * Copyright (C) 2003 - 2005 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 #include #include #include "private.h" /* move all type rules to top of t/f lists to help kernel on evaluation */ static void cond_optimize(cond_av_list_t ** l) { cond_av_list_t *top, *p, *cur; top = p = cur = *l; while (cur) { if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) { p->next = cur->next; cur->next = top; top = cur; cur = p->next; } else { p = cur; cur = cur->next; } } *l = top; } /* reorder t/f lists for kernel */ void cond_optimize_lists(cond_list_t * cl) { cond_list_t *n; for (n = cl; n != NULL; n = n->next) { cond_optimize(&n->true_list); cond_optimize(&n->false_list); } } static int bool_present(unsigned int target, unsigned int bools[], unsigned int num_bools) { unsigned int i = 0; int ret = 1; if (num_bools > COND_MAX_BOOLS) { return 0; } while (i < num_bools && target != bools[i]) i++; if (i == num_bools) ret = 0; /* got to end w/o match */ return ret; } static int same_bools(cond_node_t * a, cond_node_t * b) { unsigned int i, x; x = a->nbools; /* same number of bools? */ if (x != b->nbools) return 0; /* make sure all the bools in a are also in b */ for (i = 0; i < x; i++) if (!bool_present(a->bool_ids[i], b->bool_ids, x)) return 0; return 1; } /* * Determine if two conditional expressions are equal. */ int cond_expr_equal(cond_node_t * a, cond_node_t * b) { cond_expr_t *cur_a, *cur_b; if (a == NULL || b == NULL) return 0; if (a->nbools != b->nbools) return 0; /* if exprs have <= COND_MAX_BOOLS we can check the precompute values * for the expressions. */ if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) { if (!same_bools(a, b)) return 0; return (a->expr_pre_comp == b->expr_pre_comp); } /* for long expressions we check for exactly the same expression */ cur_a = a->expr; cur_b = b->expr; while (1) { if (cur_a == NULL && cur_b == NULL) return 1; else if (cur_a == NULL || cur_b == NULL) return 0; if (cur_a->expr_type != cur_b->expr_type) return 0; if (cur_a->expr_type == COND_BOOL) { if (cur_a->bool != cur_b->bool) return 0; } cur_a = cur_a->next; cur_b = cur_b->next; } return 1; } /* Create a new conditional node, optionally copying * the conditional expression from an existing node. * If node is NULL then a new node will be created * with no conditional expression. */ cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node) { cond_node_t *new_node; unsigned int i; new_node = (cond_node_t *)malloc(sizeof(cond_node_t)); if (!new_node) { return NULL; } memset(new_node, 0, sizeof(cond_node_t)); if (node) { new_node->expr = cond_copy_expr(node->expr); if (!new_node->expr) { free(new_node); return NULL; } new_node->cur_state = cond_evaluate_expr(p, new_node->expr); new_node->nbools = node->nbools; for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++) new_node->bool_ids[i] = node->bool_ids[i]; new_node->expr_pre_comp = node->expr_pre_comp; new_node->flags = node->flags; } return new_node; } /* Find a conditional (the needle) within a list of existing ones (the * haystack) that has a matching expression. If found, return a * pointer to the existing node, setting 'was_created' to 0. * Otherwise create a new one and return it, setting 'was_created' to * 1. */ cond_node_t *cond_node_find(policydb_t * p, cond_node_t * needle, cond_node_t * haystack, int *was_created) { while (haystack) { if (cond_expr_equal(needle, haystack)) { *was_created = 0; return haystack; } haystack = haystack->next; } *was_created = 1; return cond_node_create(p, needle); } /* return either a pre-existing matching node or create a new node */ cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list, cond_node_t * cn) { int was_created; cond_node_t *result = cond_node_find(p, cn, list, &was_created); if (result != NULL && was_created) { /* add conditional node to policy list */ result->next = p->cond_list; p->cond_list = result; } return result; } /* * cond_evaluate_expr evaluates a conditional expr * in reverse polish notation. It returns true (1), false (0), * or undefined (-1). Undefined occurs when the expression * exceeds the stack depth of COND_EXPR_MAXDEPTH. */ int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr) { cond_expr_t *cur; int s[COND_EXPR_MAXDEPTH]; int sp = -1; s[0] = -1; for (cur = expr; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: if (sp == (COND_EXPR_MAXDEPTH - 1)) return -1; sp++; s[sp] = p->bool_val_to_struct[cur->bool - 1]->state; break; case COND_NOT: if (sp < 0) return -1; s[sp] = !s[sp]; break; case COND_OR: if (sp < 1) return -1; sp--; s[sp] |= s[sp + 1]; break; case COND_AND: if (sp < 1) return -1; sp--; s[sp] &= s[sp + 1]; break; case COND_XOR: if (sp < 1) return -1; sp--; s[sp] ^= s[sp + 1]; break; case COND_EQ: if (sp < 1) return -1; sp--; s[sp] = (s[sp] == s[sp + 1]); break; case COND_NEQ: if (sp < 1) return -1; sp--; s[sp] = (s[sp] != s[sp + 1]); break; default: return -1; } } return s[0]; } cond_expr_t *cond_copy_expr(cond_expr_t * expr) { cond_expr_t *cur, *head, *tail, *new_expr; tail = head = NULL; cur = expr; while (cur) { new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t)); if (!new_expr) goto free_head; memset(new_expr, 0, sizeof(cond_expr_t)); new_expr->expr_type = cur->expr_type; new_expr->bool = cur->bool; if (!head) head = new_expr; if (tail) tail->next = new_expr; tail = new_expr; cur = cur->next; } return head; free_head: while (head) { tail = head->next; free(head); head = tail; } return NULL; } /* * evaluate_cond_node evaluates the conditional stored in * a cond_node_t and if the result is different than the * current state of the node it sets the rules in the true/false * list appropriately. If the result of the expression is undefined * all of the rules are disabled for safety. */ static int evaluate_cond_node(policydb_t * p, cond_node_t * node) { int new_state; cond_av_list_t *cur; new_state = cond_evaluate_expr(p, node->expr); if (new_state != node->cur_state) { node->cur_state = new_state; if (new_state == -1) printf ("expression result was undefined - disabling all rules.\n"); /* turn the rules on or off */ for (cur = node->true_list; cur != NULL; cur = cur->next) { if (new_state <= 0) { cur->node->key.specified &= ~AVTAB_ENABLED; } else { cur->node->key.specified |= AVTAB_ENABLED; } } for (cur = node->false_list; cur != NULL; cur = cur->next) { /* -1 or 1 */ if (new_state) { cur->node->key.specified &= ~AVTAB_ENABLED; } else { cur->node->key.specified |= AVTAB_ENABLED; } } } return 0; } /* precompute and simplify an expression if possible. If left with !expression, change * to expression and switch t and f. precompute expression for expressions with limited * number of bools. */ int cond_normalize_expr(policydb_t * p, cond_node_t * cn) { cond_expr_t *ne, *e; cond_av_list_t *tmp; unsigned int i, j, orig_value[COND_MAX_BOOLS]; int k; uint32_t test = 0x0; avrule_t *tmp2; cn->nbools = 0; memset(cn->bool_ids, 0, sizeof(cn->bool_ids)); cn->expr_pre_comp = 0x0; /* take care of !expr case */ ne = NULL; e = cn->expr; /* becuase it's RPN look at last element */ while (e->next != NULL) { ne = e; e = e->next; } if (e->expr_type == COND_NOT) { if (ne) { ne->next = NULL; } else { /* ne should never be NULL */ printf ("Found expr with no bools and only a ! - this should never happen.\n"); return -1; } /* swap the true and false lists */ tmp = cn->true_list; cn->true_list = cn->false_list; cn->false_list = tmp; tmp2 = cn->avtrue_list; cn->avtrue_list = cn->avfalse_list; cn->avfalse_list = tmp2; /* free the "not" node in the list */ free(e); } /* find all the bools in the expression */ for (e = cn->expr; e != NULL; e = e->next) { switch (e->expr_type) { case COND_BOOL: i = 0; /* see if we've already seen this bool */ if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) { /* count em all but only record up to COND_MAX_BOOLS */ if (cn->nbools < COND_MAX_BOOLS) cn->bool_ids[cn->nbools++] = e->bool; else cn->nbools++; } break; default: break; } } /* only precompute for exprs with <= COND_AX_BOOLS */ if (cn->nbools <= COND_MAX_BOOLS) { /* save the default values for the bools so we can play with them */ for (i = 0; i < cn->nbools; i++) { orig_value[i] = p->bool_val_to_struct[cn->bool_ids[i] - 1]->state; } /* loop through all possible combinations of values for bools in expression */ for (test = 0x0; test < (0x1U << cn->nbools); test++) { /* temporarily set the value for all the bools in the * expression using the corr. bit in test */ for (j = 0; j < cn->nbools; j++) { p->bool_val_to_struct[cn->bool_ids[j] - 1]->state = (test & (0x1 << j)) ? 1 : 0; } k = cond_evaluate_expr(p, cn->expr); if (k == -1) { printf ("While testing expression, expression result " "was undefined - this should never happen.\n"); return -1; } /* set the bit if expression evaluates true */ if (k) cn->expr_pre_comp |= 0x1 << test; } /* restore bool default values */ for (i = 0; i < cn->nbools; i++) p->bool_val_to_struct[cn->bool_ids[i] - 1]->state = orig_value[i]; } return 0; } int evaluate_conds(policydb_t * p) { int ret; cond_node_t *cur; for (cur = p->cond_list; cur != NULL; cur = cur->next) { ret = evaluate_cond_node(p, cur); if (ret) return ret; } return 0; } int cond_policydb_init(policydb_t * p) { p->bool_val_to_struct = NULL; p->cond_list = NULL; if (avtab_init(&p->te_cond_avtab)) return -1; return 0; } void cond_av_list_destroy(cond_av_list_t * list) { cond_av_list_t *cur, *next; for (cur = list; cur != NULL; cur = next) { next = cur->next; /* the avtab_ptr_t node is destroy by the avtab */ free(cur); } } void cond_expr_destroy(cond_expr_t * expr) { cond_expr_t *cur_expr, *next_expr; if (!expr) return; for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) { next_expr = cur_expr->next; free(cur_expr); } } void cond_node_destroy(cond_node_t * node) { if (!node) return; cond_expr_destroy(node->expr); avrule_list_destroy(node->avtrue_list); avrule_list_destroy(node->avfalse_list); cond_av_list_destroy(node->true_list); cond_av_list_destroy(node->false_list); } void cond_list_destroy(cond_list_t * list) { cond_node_t *next, *cur; if (list == NULL) return; for (cur = list; cur != NULL; cur = next) { next = cur->next; cond_node_destroy(cur); free(cur); } } void cond_policydb_destroy(policydb_t * p) { if (p->bool_val_to_struct != NULL) free(p->bool_val_to_struct); avtab_destroy(&p->te_cond_avtab); cond_list_destroy(p->cond_list); } int cond_init_bool_indexes(policydb_t * p) { if (p->bool_val_to_struct) free(p->bool_val_to_struct); p->bool_val_to_struct = (cond_bool_datum_t **) malloc(p->p_bools.nprim * sizeof(cond_bool_datum_t *)); if (!p->bool_val_to_struct) return -1; return 0; } int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { if (key) free(key); free(datum); return 0; } int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; cond_bool_datum_t *booldatum; booldatum = datum; p = datap; if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim) return -EINVAL; p->p_bool_val_to_name[booldatum->s.value - 1] = key; p->bool_val_to_struct[booldatum->s.value - 1] = booldatum; return 0; } static int bool_isvalid(cond_bool_datum_t * b) { if (!(b->state == 0 || b->state == 1)) return 0; return 1; } int cond_read_bool(policydb_t * p, hashtab_t h, struct policy_file *fp) { char *key = 0; cond_bool_datum_t *booldatum; uint32_t buf[3], len; int rc; booldatum = malloc(sizeof(cond_bool_datum_t)); if (!booldatum) return -1; memset(booldatum, 0, sizeof(cond_bool_datum_t)); rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) goto err; booldatum->s.value = le32_to_cpu(buf[0]); booldatum->state = le32_to_cpu(buf[1]); if (!bool_isvalid(booldatum)) goto err; len = le32_to_cpu(buf[2]); key = malloc(len + 1); if (!key) goto err; rc = next_entry(key, fp, len); if (rc < 0) goto err; key[len] = 0; if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto err; booldatum->flags = le32_to_cpu(buf[0]); } if (hashtab_insert(h, key, booldatum)) goto err; return 0; err: cond_destroy_bool(key, booldatum, 0); return -1; } struct cond_insertf_data { struct policydb *p; cond_av_list_t *other; cond_av_list_t *head; cond_av_list_t *tail; }; static int cond_insertf(avtab_t * a __attribute__ ((unused)), avtab_key_t * k, avtab_datum_t * d, void *ptr) { struct cond_insertf_data *data = ptr; struct policydb *p = data->p; cond_av_list_t *other = data->other, *list, *cur; avtab_ptr_t node_ptr; uint8_t found; /* * For type rules we have to make certain there aren't any * conflicting rules by searching the te_avtab and the * cond_te_avtab. */ if (k->specified & AVTAB_TYPE) { if (avtab_search(&p->te_avtab, k)) { printf ("security: type rule already exists outside of a conditional."); goto err; } /* * If we are reading the false list other will be a pointer to * the true list. We can have duplicate entries if there is only * 1 other entry and it is in our true list. * * If we are reading the true list (other == NULL) there shouldn't * be any other entries. */ if (other) { node_ptr = avtab_search_node(&p->te_cond_avtab, k); if (node_ptr) { if (avtab_search_node_next (node_ptr, k->specified)) { printf ("security: too many conflicting type rules."); goto err; } found = 0; for (cur = other; cur != NULL; cur = cur->next) { if (cur->node == node_ptr) { found = 1; break; } } if (!found) { printf ("security: conflicting type rules.\n"); goto err; } } } else { if (avtab_search(&p->te_cond_avtab, k)) { printf ("security: conflicting type rules when adding type rule for true.\n"); goto err; } } } node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); if (!node_ptr) { printf("security: could not insert rule."); goto err; } node_ptr->parse_context = (void *)1; list = malloc(sizeof(cond_av_list_t)); if (!list) goto err; memset(list, 0, sizeof(cond_av_list_t)); list->node = node_ptr; if (!data->head) data->head = list; else data->tail->next = list; data->tail = list; return 0; err: cond_av_list_destroy(data->head); data->head = NULL; return -1; } static int cond_read_av_list(policydb_t * p, void *fp, cond_av_list_t ** ret_list, cond_av_list_t * other) { unsigned int i; int rc; uint32_t buf[1], len; struct cond_insertf_data data; *ret_list = NULL; len = 0; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; len = le32_to_cpu(buf[0]); if (len == 0) { return 0; } data.p = p; data.other = other; data.head = NULL; data.tail = NULL; for (i = 0; i < len; i++) { rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data); if (rc) return rc; } *ret_list = data.head; return 0; } static int expr_isvalid(policydb_t * p, cond_expr_t * expr) { if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { printf ("security: conditional expressions uses unknown operator.\n"); return 0; } if (expr->bool > p->p_bools.nprim) { printf ("security: conditional expressions uses unknown bool.\n"); return 0; } return 1; } static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp) { uint32_t buf[2]; int len, i, rc; cond_expr_t *expr = NULL, *last = NULL; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto err; node->cur_state = le32_to_cpu(buf[0]); len = 0; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto err; /* expr */ len = le32_to_cpu(buf[0]); for (i = 0; i < len; i++) { rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) goto err; expr = malloc(sizeof(cond_expr_t)); if (!expr) { goto err; } memset(expr, 0, sizeof(cond_expr_t)); expr->expr_type = le32_to_cpu(buf[0]); expr->bool = le32_to_cpu(buf[1]); if (!expr_isvalid(p, expr)) { free(expr); goto err; } if (i == 0) { node->expr = expr; } else { last->next = expr; } last = expr; } if (p->policy_type == POLICY_KERN) { if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0) goto err; if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0) goto err; } else { if (avrule_read_list(p, &node->avtrue_list, fp)) goto err; if (avrule_read_list(p, &node->avfalse_list, fp)) goto err; } if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto err; node->flags = le32_to_cpu(buf[0]); } return 0; err: cond_node_destroy(node); free(node); return -1; } int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp) { cond_node_t *node, *last = NULL; uint32_t buf[1]; int i, len, rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; len = le32_to_cpu(buf[0]); rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel); if (rc) goto err; for (i = 0; i < len; i++) { node = malloc(sizeof(cond_node_t)); if (!node) goto err; memset(node, 0, sizeof(cond_node_t)); if (cond_read_node(p, node, fp) != 0) goto err; if (i == 0) { *list = node; } else { last->next = node; } last = node; } return 0; err: return -1; } /* Determine whether additional permissions are granted by the conditional * av table, and if so, add them to the result */ void cond_compute_av(avtab_t * ctab, avtab_key_t * key, struct sepol_av_decision *avd) { avtab_ptr_t node; if (!ctab || !key || !avd) return; for (node = avtab_search_node(ctab, key); node != NULL; node = avtab_search_node_next(node, key->specified)) { if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) == (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED))) avd->allowed |= node->datum.data; if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a * permission we do NOT want to audit (dontaudit), we use * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ avd->auditdeny &= node->datum.data; if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED))) avd->auditallow |= node->datum.data; } return; } avtab_datum_t *cond_av_list_search(avtab_key_t * key, cond_av_list_t * cond_list) { cond_av_list_t *cur_av; for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) { if (cur_av->node->key.source_type == key->source_type && cur_av->node->key.target_type == key->target_type && cur_av->node->key.target_class == key->target_class) return &cur_av->node->datum; } return NULL; } libsepol-2.2/src/constraint.c000066400000000000000000000027131223423440700163110ustar00rootroot00000000000000/* Authors: Jason Tang * * Copyright (C) 2005 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 #include #include #include #include #include int constraint_expr_init(constraint_expr_t * expr) { memset(expr, 0, sizeof(*expr)); ebitmap_init(&expr->names); if ((expr->type_names = malloc(sizeof(*expr->type_names))) == NULL) { return -1; } type_set_init(expr->type_names); return 0; } void constraint_expr_destroy(constraint_expr_t * expr) { if (expr != NULL) { ebitmap_destroy(&expr->names); type_set_destroy(expr->type_names); free(expr->type_names); free(expr); } } libsepol-2.2/src/context.c000066400000000000000000000177671223423440700156300ustar00rootroot00000000000000#include #include #include #include #include #include "context_internal.h" #include "debug.h" #include "context.h" #include "handle.h" #include "mls.h" /* ----- Compatibility ---- */ int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c) { return context_is_valid(p, c); } int sepol_check_context(const char *context) { return sepol_context_to_sid((const sepol_security_context_t)context, strlen(context) + 1, NULL); } /* ---- End compatibility --- */ /* * Return 1 if the fields in the security context * structure `c' are valid. Return 0 otherwise. */ int context_is_valid(const policydb_t * p, const context_struct_t * c) { role_datum_t *role; user_datum_t *usrdatum; ebitmap_t types, roles; int ret = 1; ebitmap_init(&types); ebitmap_init(&roles); if (!c->role || c->role > p->p_roles.nprim) return 0; if (!c->user || c->user > p->p_users.nprim) return 0; if (!c->type || c->type > p->p_types.nprim) return 0; if (c->role != OBJECT_R_VAL) { /* * Role must be authorized for the type. */ role = p->role_val_to_struct[c->role - 1]; if (!ebitmap_get_bit(&role->cache, c->type - 1)) /* role may not be associated with type */ return 0; /* * User must be authorized for the role. */ usrdatum = p->user_val_to_struct[c->user - 1]; if (!usrdatum) return 0; if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1)) /* user may not be associated with role */ return 0; } if (!mls_context_isvalid(p, c)) return 0; return ret; } /* * Write the security context string representation of * the context structure `context' into a dynamically * allocated string of the correct size. Set `*scontext' * to point to this string and set `*scontext_len' to * the length of the string. */ int context_to_string(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * context, char **result, size_t * result_len) { char *scontext = NULL; size_t scontext_len = 0; char *ptr; /* Compute the size of the context. */ scontext_len += strlen(policydb->p_user_val_to_name[context->user - 1]) + 1; scontext_len += strlen(policydb->p_role_val_to_name[context->role - 1]) + 1; scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]); scontext_len += mls_compute_context_len(policydb, context); /* We must null terminate the string */ scontext_len += 1; /* Allocate space for the context; caller must free this space. */ scontext = malloc(scontext_len); if (!scontext) goto omem; scontext[scontext_len - 1] = '\0'; /* * Copy the user name, role name and type name into the context. */ ptr = scontext; sprintf(ptr, "%s:%s:%s", policydb->p_user_val_to_name[context->user - 1], policydb->p_role_val_to_name[context->role - 1], policydb->p_type_val_to_name[context->type - 1]); ptr += strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 + strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 + strlen(policydb->p_type_val_to_name[context->type - 1]); mls_sid_to_context(policydb, context, &ptr); *result = scontext; *result_len = scontext_len; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not convert " "context to string"); free(scontext); return STATUS_ERR; } /* * Create a context structure from the given record */ int context_from_record(sepol_handle_t * handle, const policydb_t * policydb, context_struct_t ** cptr, const sepol_context_t * record) { context_struct_t *scontext = NULL; user_datum_t *usrdatum; role_datum_t *roldatum; type_datum_t *typdatum; /* Hashtab keys are not constant - suppress warnings */ char *user = strdup(sepol_context_get_user(record)); char *role = strdup(sepol_context_get_role(record)); char *type = strdup(sepol_context_get_type(record)); const char *mls = sepol_context_get_mls(record); scontext = (context_struct_t *) malloc(sizeof(context_struct_t)); if (!user || !role || !type || !scontext) { ERR(handle, "out of memory"); goto err; } context_init(scontext); /* User */ usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table, (hashtab_key_t) user); if (!usrdatum) { ERR(handle, "user %s is not defined", user); goto err_destroy; } scontext->user = usrdatum->s.value; /* Role */ roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table, (hashtab_key_t) role); if (!roldatum) { ERR(handle, "role %s is not defined", role); goto err_destroy; } scontext->role = roldatum->s.value; /* Type */ typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table, (hashtab_key_t) type); if (!typdatum || typdatum->flavor == TYPE_ATTRIB) { ERR(handle, "type %s is not defined", type); goto err_destroy; } scontext->type = typdatum->s.value; /* MLS */ if (mls && !policydb->mls) { ERR(handle, "MLS is disabled, but MLS context \"%s\" found", mls); goto err_destroy; } else if (!mls && policydb->mls) { ERR(handle, "MLS is enabled, but no MLS context found"); goto err_destroy; } if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0)) goto err_destroy; /* Validity check */ if (!context_is_valid(policydb, scontext)) { if (mls) { ERR(handle, "invalid security context: \"%s:%s:%s:%s\"", user, role, type, mls); } else { ERR(handle, "invalid security context: \"%s:%s:%s\"", user, role, type); } goto err_destroy; } *cptr = scontext; free(user); free(type); free(role); return STATUS_SUCCESS; err_destroy: errno = EINVAL; context_destroy(scontext); err: free(scontext); free(user); free(type); free(role); ERR(handle, "could not create context structure"); return STATUS_ERR; } /* * Create a record from the given context structure */ int context_to_record(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * context, sepol_context_t ** record) { sepol_context_t *tmp_record = NULL; char *mls = NULL; if (sepol_context_create(handle, &tmp_record) < 0) goto err; if (sepol_context_set_user(handle, tmp_record, policydb->p_user_val_to_name[context->user - 1]) < 0) goto err; if (sepol_context_set_role(handle, tmp_record, policydb->p_role_val_to_name[context->role - 1]) < 0) goto err; if (sepol_context_set_type(handle, tmp_record, policydb->p_type_val_to_name[context->type - 1]) < 0) goto err; if (policydb->mls) { if (mls_to_string(handle, policydb, context, &mls) < 0) goto err; if (sepol_context_set_mls(handle, tmp_record, mls) < 0) goto err; } free(mls); *record = tmp_record; return STATUS_SUCCESS; err: ERR(handle, "could not create context record"); sepol_context_free(tmp_record); free(mls); return STATUS_ERR; } /* * Create a context structure from the provided string. */ int context_from_string(sepol_handle_t * handle, const policydb_t * policydb, context_struct_t ** cptr, const char *con_str, size_t con_str_len) { char *con_cpy = NULL; sepol_context_t *ctx_record = NULL; /* sepol_context_from_string expects a NULL-terminated string */ con_cpy = malloc(con_str_len + 1); if (!con_cpy) goto omem; memcpy(con_cpy, con_str, con_str_len); con_cpy[con_str_len] = '\0'; if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0) goto err; /* Now create from the data structure */ if (context_from_record(handle, policydb, cptr, ctx_record) < 0) goto err; free(con_cpy); sepol_context_free(ctx_record); return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not create context structure"); free(con_cpy); sepol_context_free(ctx_record); return STATUS_ERR; } int sepol_context_check(sepol_handle_t * handle, const sepol_policydb_t * policydb, const sepol_context_t * context) { context_struct_t *con = NULL; int ret = context_from_record(handle, &policydb->p, &con, context); context_destroy(con); free(con); return ret; } libsepol-2.2/src/context.h000066400000000000000000000023471223423440700156210ustar00rootroot00000000000000#ifndef _SEPOL_INTERNAL_CONTEXT_H_ #define _SEPOL_INTERNAL_CONTEXT_H_ #include #include "context_internal.h" #include #include #include /* Create a context structure from high level representation */ extern int context_from_record(sepol_handle_t * handle, const policydb_t * policydb, context_struct_t ** cptr, const sepol_context_t * data); extern int context_to_record(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * context, sepol_context_t ** record); /* Create a context structure from string representation */ extern int context_from_string(sepol_handle_t * handle, const policydb_t * policydb, context_struct_t ** cptr, const char *con_str, size_t con_str_len); /* Check if the provided context is valid for this policy */ extern int context_is_valid(const policydb_t * policydb, const context_struct_t * context); /* Extract the context as string */ extern int context_to_string(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * context, char **result, size_t * result_len); #endif libsepol-2.2/src/context_internal.h000066400000000000000000000011421223423440700175050ustar00rootroot00000000000000#ifndef _SEPOL_CONTEXT_INTERNAL_H_ #define _SEPOL_CONTEXT_INTERNAL_H_ #include #include "dso.h" hidden_proto(sepol_context_clone) hidden_proto(sepol_context_create) hidden_proto(sepol_context_free) hidden_proto(sepol_context_from_string) hidden_proto(sepol_context_get_mls) hidden_proto(sepol_context_get_role) hidden_proto(sepol_context_get_type) hidden_proto(sepol_context_get_user) hidden_proto(sepol_context_set_mls) hidden_proto(sepol_context_set_role) hidden_proto(sepol_context_set_type) hidden_proto(sepol_context_set_user) #endif libsepol-2.2/src/context_record.c000066400000000000000000000137421223423440700171530ustar00rootroot00000000000000#include #include #include #include #include "context_internal.h" #include "debug.h" struct sepol_context { /* Selinux user */ char *user; /* Selinux role */ char *role; /* Selinux type */ char *type; /* MLS */ char *mls; }; /* User */ const char *sepol_context_get_user(const sepol_context_t * con) { return con->user; } hidden_def(sepol_context_get_user) int sepol_context_set_user(sepol_handle_t * handle, sepol_context_t * con, const char *user) { char *tmp_user = strdup(user); if (!tmp_user) { ERR(handle, "out of memory, could not set " "context user to %s", user); return STATUS_ERR; } free(con->user); con->user = tmp_user; return STATUS_SUCCESS; } hidden_def(sepol_context_set_user) /* Role */ const char *sepol_context_get_role(const sepol_context_t * con) { return con->role; } hidden_def(sepol_context_get_role) int sepol_context_set_role(sepol_handle_t * handle, sepol_context_t * con, const char *role) { char *tmp_role = strdup(role); if (!tmp_role) { ERR(handle, "out of memory, could not set " "context role to %s", role); return STATUS_ERR; } free(con->role); con->role = tmp_role; return STATUS_SUCCESS; } hidden_def(sepol_context_set_role) /* Type */ const char *sepol_context_get_type(const sepol_context_t * con) { return con->type; } hidden_def(sepol_context_get_type) int sepol_context_set_type(sepol_handle_t * handle, sepol_context_t * con, const char *type) { char *tmp_type = strdup(type); if (!tmp_type) { ERR(handle, "out of memory, could not set " "context type to %s", type); return STATUS_ERR; } free(con->type); con->type = tmp_type; return STATUS_SUCCESS; } hidden_def(sepol_context_set_type) /* MLS */ const char *sepol_context_get_mls(const sepol_context_t * con) { return con->mls; } hidden_def(sepol_context_get_mls) int sepol_context_set_mls(sepol_handle_t * handle, sepol_context_t * con, const char *mls) { char *tmp_mls = strdup(mls); if (!tmp_mls) { ERR(handle, "out of memory, could not set " "MLS fields to %s", mls); return STATUS_ERR; } free(con->mls); con->mls = tmp_mls; return STATUS_SUCCESS; } hidden_def(sepol_context_set_mls) /* Create */ int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr) { sepol_context_t *con = (sepol_context_t *) malloc(sizeof(sepol_context_t)); if (!con) { ERR(handle, "out of memory, could not " "create context\n"); return STATUS_ERR; } con->user = NULL; con->role = NULL; con->type = NULL; con->mls = NULL; *con_ptr = con; return STATUS_SUCCESS; } hidden_def(sepol_context_create) /* Deep copy clone */ int sepol_context_clone(sepol_handle_t * handle, const sepol_context_t * con, sepol_context_t ** con_ptr) { sepol_context_t *new_con = NULL; if (!con) { *con_ptr = NULL; return 0; } if (sepol_context_create(handle, &new_con) < 0) goto err; if (!(new_con->user = strdup(con->user))) goto omem; if (!(new_con->role = strdup(con->role))) goto omem; if (!(new_con->type = strdup(con->type))) goto omem; if (con->mls && !(new_con->mls = strdup(con->mls))) goto omem; *con_ptr = new_con; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not clone context record"); sepol_context_free(new_con); return STATUS_ERR; } hidden_def(sepol_context_clone) /* Destroy */ void sepol_context_free(sepol_context_t * con) { if (!con) return; free(con->user); free(con->role); free(con->type); free(con->mls); free(con); } hidden_def(sepol_context_free) int sepol_context_from_string(sepol_handle_t * handle, const char *str, sepol_context_t ** con) { char *tmp = NULL, *low, *high; sepol_context_t *tmp_con = NULL; if (!strcmp(str, "<>")) { *con = NULL; return STATUS_SUCCESS; } if (sepol_context_create(handle, &tmp_con) < 0) goto err; /* Working copy context */ tmp = strdup(str); if (!tmp) { ERR(handle, "out of memory"); goto err; } low = tmp; /* Then, break it into its components */ /* User */ if (!(high = strchr(low, ':'))) goto mcontext; else *high++ = '\0'; if (sepol_context_set_user(handle, tmp_con, low) < 0) goto err; low = high; /* Role */ if (!(high = strchr(low, ':'))) goto mcontext; else *high++ = '\0'; if (sepol_context_set_role(handle, tmp_con, low) < 0) goto err; low = high; /* Type, and possibly MLS */ if (!(high = strchr(low, ':'))) { if (sepol_context_set_type(handle, tmp_con, low) < 0) goto err; } else { *high++ = '\0'; if (sepol_context_set_type(handle, tmp_con, low) < 0) goto err; low = high; if (sepol_context_set_mls(handle, tmp_con, low) < 0) goto err; } free(tmp); *con = tmp_con; return STATUS_SUCCESS; mcontext: errno = EINVAL; ERR(handle, "malformed context \"%s\"", str); err: ERR(handle, "could not construct context from string"); free(tmp); sepol_context_free(tmp_con); return STATUS_ERR; } hidden_def(sepol_context_from_string) int sepol_context_to_string(sepol_handle_t * handle, const sepol_context_t * con, char **str_ptr) { int rc; const int user_sz = strlen(con->user); const int role_sz = strlen(con->role); const int type_sz = strlen(con->type); const int mls_sz = (con->mls) ? strlen(con->mls) : 0; const int total_sz = user_sz + role_sz + type_sz + mls_sz + ((con->mls) ? 3 : 2); char *str = (char *)malloc(total_sz + 1); if (!str) goto omem; if (con->mls) { rc = snprintf(str, total_sz + 1, "%s:%s:%s:%s", con->user, con->role, con->type, con->mls); if (rc < 0 || (rc >= total_sz + 1)) { ERR(handle, "print error"); goto err; } } else { rc = snprintf(str, total_sz + 1, "%s:%s:%s", con->user, con->role, con->type); if (rc < 0 || (rc >= total_sz + 1)) { ERR(handle, "print error"); goto err; } } *str_ptr = str; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not convert context to string"); free(str); return STATUS_ERR; } libsepol-2.2/src/debug.c000066400000000000000000000032611223423440700152120ustar00rootroot00000000000000#include #include #include #include "handle.h" #include "debug.h" /* Deprecated */ struct sepol_handle sepol_compat_handle = { .msg_callback = sepol_msg_default_handler, .msg_callback_arg = NULL, }; void sepol_debug(int on) { sepol_compat_handle.msg_callback = (on) ? sepol_msg_default_handler : NULL; } /* End deprecated */ int sepol_msg_get_level(sepol_handle_t * handle) { return handle->msg_level; } hidden_def(sepol_msg_get_level) const char *sepol_msg_get_channel(sepol_handle_t * handle) { return handle->msg_channel; } hidden_def(sepol_msg_get_channel) const char *sepol_msg_get_fname(sepol_handle_t * handle) { return handle->msg_fname; } hidden_def(sepol_msg_get_fname) #ifdef __GNUC__ __attribute__ ((format(printf, 3, 4))) #endif void hidden sepol_msg_default_handler(void *varg __attribute__ ((unused)), sepol_handle_t * handle, const char *fmt, ...) { FILE *stream = NULL; switch (sepol_msg_get_level(handle)) { case SEPOL_MSG_ERR: case SEPOL_MSG_WARN: stream = stderr; break; case SEPOL_MSG_INFO: default: stream = stdout; break; } fprintf(stream, "%s.%s: ", sepol_msg_get_channel(handle), sepol_msg_get_fname(handle)); va_list ap; va_start(ap, fmt); vfprintf(stream, fmt, ap); va_end(ap); fprintf(stream, "\n"); varg = NULL; } extern void sepol_msg_set_callback(sepol_handle_t * handle, #ifdef __GNUC__ __attribute__ ((format(printf, 3, 4))) #endif void (*msg_callback) (void *varg, sepol_handle_t * handle, const char *fmt, ...), void *msg_callback_arg) { handle->msg_callback = msg_callback; handle->msg_callback_arg = msg_callback_arg; } libsepol-2.2/src/debug.h000066400000000000000000000046171223423440700152250ustar00rootroot00000000000000/* * 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 */ #ifndef _SEPOL_INTERNAL_DEBUG_H_ #define _SEPOL_INTERNAL_DEBUG_H_ #include #include #include "dso.h" #include "handle.h" #define STATUS_SUCCESS 0 #define STATUS_ERR -1 #define STATUS_NODATA 1 /* FIXME: this needs to become a real function. Declaring variables * in a macro is _evil_ as it can shadow other variables in local scope. * The variable h has been renamed to _sepol_h to reduce this chance, but * it is still wrong. */ #define msg_write(handle_arg, level_arg, \ channel_arg, func_arg, ...) do { \ sepol_handle_t *_sepol_h = (handle_arg) ?: &sepol_compat_handle; \ if (_sepol_h->msg_callback) { \ _sepol_h->msg_fname = func_arg; \ _sepol_h->msg_channel = channel_arg; \ _sepol_h->msg_level = level_arg; \ \ _sepol_h->msg_callback( \ _sepol_h->msg_callback_arg, \ _sepol_h, __VA_ARGS__); \ } \ } while(0) #define ERR(handle, ...) \ msg_write(handle, SEPOL_MSG_ERR, "libsepol", \ __FUNCTION__, __VA_ARGS__) #define INFO(handle, ...) \ msg_write(handle, SEPOL_MSG_INFO, "libsepol", \ __FUNCTION__, __VA_ARGS__) #define WARN(handle, ...) \ msg_write(handle, SEPOL_MSG_WARN, "libsepol", \ __FUNCTION__, __VA_ARGS__) #ifdef __GNUC__ __attribute__ ((format(printf, 3, 4))) #endif extern void hidden sepol_msg_default_handler(void *varg, sepol_handle_t * msg, const char *fmt, ...); extern struct sepol_handle sepol_compat_handle; hidden_proto(sepol_msg_get_channel) hidden_proto(sepol_msg_get_fname) hidden_proto(sepol_msg_get_level) #endif libsepol-2.2/src/dso.h000066400000000000000000000012041223423440700147110ustar00rootroot00000000000000#ifndef _SEPOL_DSO_H #define _SEPOL_DSO_H 1 #ifdef SHARED # define hidden __attribute__ ((visibility ("hidden"))) # define hidden_proto(fct) __hidden_proto (fct, fct##_internal) # define __hidden_proto(fct, internal) \ extern __typeof (fct) internal; \ extern __typeof (fct) fct __asm (#internal) hidden; # if defined(__alpha__) || defined(__mips__) # define hidden_def(fct) \ asm (".globl " #fct "\n" #fct " = " #fct "_internal"); # else # define hidden_def(fct) \ asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); #endif #else # define hidden # define hidden_proto(fct) # define hidden_def(fct) #endif #endif libsepol-2.2/src/ebitmap.c000066400000000000000000000204471223423440700155520ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * Implementation of the extensible bitmap type. */ #include #include #include #include "debug.h" #include "private.h" int ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2) { ebitmap_node_t *n1, *n2, *new, *prev; ebitmap_init(dst); n1 = e1->node; n2 = e2->node; prev = 0; while (n1 || n2) { new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t)); if (!new) { ebitmap_destroy(dst); return -ENOMEM; } memset(new, 0, sizeof(ebitmap_node_t)); if (n1 && n2 && n1->startbit == n2->startbit) { new->startbit = n1->startbit; new->map = n1->map | n2->map; n1 = n1->next; n2 = n2->next; } else if (!n2 || (n1 && n1->startbit < n2->startbit)) { new->startbit = n1->startbit; new->map = n1->map; n1 = n1->next; } else { new->startbit = n2->startbit; new->map = n2->map; n2 = n2->next; } new->next = 0; if (prev) prev->next = new; else dst->node = new; prev = new; } dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit; return 0; } int ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1) { ebitmap_t tmp; if (ebitmap_or(&tmp, dst, e1)) return -1; ebitmap_destroy(dst); dst->node = tmp.node; dst->highbit = tmp.highbit; return 0; } int ebitmap_and(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) { unsigned int i, length = min(ebitmap_length(e1), ebitmap_length(e2)); ebitmap_init(dst); for (i=0; i < length; i++) { if (ebitmap_get_bit(e1, i) && ebitmap_get_bit(e2, i)) { int rc = ebitmap_set_bit(dst, i, 1); if (rc < 0) return rc; } } return 0; } int ebitmap_xor(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2) { unsigned int i, length = max(ebitmap_length(e1), ebitmap_length(e2)); ebitmap_init(dst); for (i=0; i < length; i++) { int val = ebitmap_get_bit(e1, i) ^ ebitmap_get_bit(e2, i); int rc = ebitmap_set_bit(dst, i, val); if (rc < 0) return rc; } return 0; } int ebitmap_not(ebitmap_t *dst, ebitmap_t *e1, unsigned int maxbit) { unsigned int i; ebitmap_init(dst); for (i=0; i < maxbit; i++) { int val = ebitmap_get_bit(e1, i); int rc = ebitmap_set_bit(dst, i, !val); if (rc < 0) return rc; } return 0; } int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int maxbit) { ebitmap_t e3; ebitmap_init(dst); int rc = ebitmap_not(&e3, e2, maxbit); if (rc < 0) return rc; rc = ebitmap_and(dst, e1, &e3); ebitmap_destroy(&e3); if (rc < 0) return rc; return 0; } unsigned int ebitmap_cardinality(ebitmap_t *e1) { unsigned int i, count = 0; for (i=ebitmap_startbit(e1); i < ebitmap_length(e1); i++) if (ebitmap_get_bit(e1, i)) count++; return count; } int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2) { if (ebitmap_cmp(e1, e2)) return 0; ebitmap_t tmp; int rc = ebitmap_xor(&tmp, e1, e2); if (rc < 0) return -1; int distance = ebitmap_cardinality(&tmp); ebitmap_destroy(&tmp); return distance; } int ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2) { ebitmap_node_t *n1, *n2; if (e1->highbit != e2->highbit) return 0; n1 = e1->node; n2 = e2->node; while (n1 && n2 && (n1->startbit == n2->startbit) && (n1->map == n2->map)) { n1 = n1->next; n2 = n2->next; } if (n1 || n2) return 0; return 1; } int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src) { ebitmap_node_t *n, *new, *prev; ebitmap_init(dst); n = src->node; prev = 0; while (n) { new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t)); if (!new) { ebitmap_destroy(dst); return -ENOMEM; } memset(new, 0, sizeof(ebitmap_node_t)); new->startbit = n->startbit; new->map = n->map; new->next = 0; if (prev) prev->next = new; else dst->node = new; prev = new; n = n->next; } dst->highbit = src->highbit; return 0; } int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2) { ebitmap_node_t *n1, *n2; if (e1->highbit < e2->highbit) return 0; n1 = e1->node; n2 = e2->node; while (n1 && n2 && (n1->startbit <= n2->startbit)) { if (n1->startbit < n2->startbit) { n1 = n1->next; continue; } if ((n1->map & n2->map) != n2->map) return 0; n1 = n1->next; n2 = n2->next; } if (n2) return 0; return 1; } int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit) { ebitmap_node_t *n; if (e->highbit < bit) return 0; n = e->node; while (n && (n->startbit <= bit)) { if ((n->startbit + MAPSIZE) > bit) { if (n->map & (MAPBIT << (bit - n->startbit))) return 1; else return 0; } n = n->next; } return 0; } int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value) { ebitmap_node_t *n, *prev, *new; uint32_t startbit = bit & ~(MAPSIZE - 1); uint32_t highbit = startbit + MAPSIZE; if (highbit == 0) { ERR(NULL, "bitmap overflow, bit 0x%x", bit); return -EINVAL; } prev = 0; n = e->node; while (n && n->startbit <= bit) { if ((n->startbit + MAPSIZE) > bit) { if (value) { n->map |= (MAPBIT << (bit - n->startbit)); } else { n->map &= ~(MAPBIT << (bit - n->startbit)); if (!n->map) { /* drop this node from the bitmap */ if (!n->next) { /* * this was the highest map * within the bitmap */ if (prev) e->highbit = prev->startbit + MAPSIZE; else e->highbit = 0; } if (prev) prev->next = n->next; else e->node = n->next; free(n); } } return 0; } prev = n; n = n->next; } if (!value) return 0; new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t)); if (!new) return -ENOMEM; memset(new, 0, sizeof(ebitmap_node_t)); new->startbit = startbit; new->map = (MAPBIT << (bit - new->startbit)); if (!n) { /* this node will be the highest map within the bitmap */ e->highbit = highbit; } if (prev) { new->next = prev->next; prev->next = new; } else { new->next = e->node; e->node = new; } return 0; } void ebitmap_destroy(ebitmap_t * e) { ebitmap_node_t *n, *temp; if (!e) return; n = e->node; while (n) { temp = n; n = n->next; free(temp); } e->highbit = 0; e->node = 0; return; } int ebitmap_read(ebitmap_t * e, void *fp) { int rc; ebitmap_node_t *n, *l; uint32_t buf[3], mapsize, count, i; uint64_t map; ebitmap_init(e); rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) goto bad; mapsize = le32_to_cpu(buf[0]); e->highbit = le32_to_cpu(buf[1]); count = le32_to_cpu(buf[2]); if (mapsize != MAPSIZE) { printf ("security: ebitmap: map size %d does not match my size %zu (high bit was %d)\n", mapsize, MAPSIZE, e->highbit); goto bad; } if (!e->highbit) { e->node = NULL; goto ok; } if (e->highbit & (MAPSIZE - 1)) { printf ("security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)\n", e->highbit, MAPSIZE); goto bad; } l = NULL; for (i = 0; i < count; i++) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { printf("security: ebitmap: truncated map\n"); goto bad; } n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t)); if (!n) { printf("security: ebitmap: out of memory\n"); rc = -ENOMEM; goto bad; } memset(n, 0, sizeof(ebitmap_node_t)); n->startbit = le32_to_cpu(buf[0]); if (n->startbit & (MAPSIZE - 1)) { printf ("security: ebitmap start bit (%d) is not a multiple of the map size (%zu)\n", n->startbit, MAPSIZE); goto bad_free; } if (n->startbit > (e->highbit - MAPSIZE)) { printf ("security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)\n", n->startbit, (e->highbit - MAPSIZE)); goto bad_free; } rc = next_entry(&map, fp, sizeof(uint64_t)); if (rc < 0) { printf("security: ebitmap: truncated map\n"); goto bad_free; } n->map = le64_to_cpu(map); if (!n->map) { printf ("security: ebitmap: null map in ebitmap (startbit %d)\n", n->startbit); goto bad_free; } if (l) { if (n->startbit <= l->startbit) { printf ("security: ebitmap: start bit %d comes after start bit %d\n", n->startbit, l->startbit); goto bad_free; } l->next = n; } else e->node = n; l = n; } ok: rc = 0; out: return rc; bad_free: free(n); bad: if (!rc) rc = -EINVAL; ebitmap_destroy(e); goto out; } /* FLASK */ libsepol-2.2/src/expand.c000066400000000000000000002525241223423440700154130ustar00rootroot00000000000000/* Authors: Karl MacMillan * Jason Tang * Joshua Brindle * * Copyright (C) 2004-2005 Tresys Technology, LLC * Copyright (C) 2007 Red Hat, Inc. * * 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 "context.h" #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "private.h" typedef struct expand_state { int verbose; uint32_t *typemap; uint32_t *boolmap; uint32_t *rolemap; uint32_t *usermap; policydb_t *base; policydb_t *out; sepol_handle_t *handle; int expand_neverallow; } expand_state_t; struct linear_probe { filename_trans_t **table; /* filename_trans chunks with same stype */ filename_trans_t **ends; /* pointers to ends of **table chunks */ uint32_t length; /* length of the table */ }; static int linear_probe_create(struct linear_probe *probe, uint32_t length) { probe->table = calloc(length, sizeof(*probe->table)); if (probe->table == NULL) return -1; probe->ends = calloc(length, sizeof(*probe->ends)); if (probe->ends == NULL) return -1; probe->length = length; return 0; } static void linear_probe_destroy(struct linear_probe *probe) { if (probe->length == 0) return; free(probe->table); free(probe->ends); memset(probe, 0, sizeof(*probe)); } static void linear_probe_insert(struct linear_probe *probe, uint32_t key, filename_trans_t *data) { assert(probe->length > key); if (probe->table[key] != NULL) { data->next = probe->table[key]; probe->table[key] = data; } else { probe->table[key] = probe->ends[key] = data; } } static filename_trans_t *linear_probe_find(struct linear_probe *probe, uint32_t key) { assert(probe->length > key); return probe->table[key]; } /* Returns all chunks stored in the *probe as single-linked list */ static filename_trans_t *linear_probe_dump(struct linear_probe *probe, filename_trans_t **endp) { uint32_t i; filename_trans_t *result = NULL; filename_trans_t *end = NULL; for (i = 0; i < probe->length; i++) { if (probe->table[i] != NULL) { if (end == NULL) end = probe->ends[i]; probe->ends[i]->next = result; result = probe->table[i]; probe->table[i] = probe->ends[i] = NULL; } } /* Incoherent result and end pointers indicates bug */ assert((result != NULL && end != NULL) || (result == NULL && end == NULL)); *endp = end; return result; } static void expand_state_init(expand_state_t * state) { memset(state, 0, sizeof(expand_state_t)); } static int map_ebitmap(ebitmap_t * src, ebitmap_t * dst, uint32_t * map) { unsigned int i; ebitmap_node_t *tnode; ebitmap_init(dst); ebitmap_for_each_bit(src, tnode, i) { if (!ebitmap_node_get_bit(tnode, i)) continue; if (!map[i]) continue; if (ebitmap_set_bit(dst, map[i] - 1, 1)) return -1; } return 0; } static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; type_datum_t *type, *new_type; expand_state_t *state; id = (char *)key; type = (type_datum_t *) datum; state = (expand_state_t *) data; if ((type->flavor == TYPE_TYPE && !type->primary) || type->flavor == TYPE_ALIAS) { /* aliases are handled later */ return 0; } if (!is_id_enabled(id, state->base, SYM_TYPES)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying type or attribute %s", id); new_id = strdup(id); if (new_id == NULL) { ERR(state->handle, "Out of memory!"); return -1; } new_type = (type_datum_t *) malloc(sizeof(type_datum_t)); if (!new_type) { ERR(state->handle, "Out of memory!"); free(new_id); return SEPOL_ENOMEM; } memset(new_type, 0, sizeof(type_datum_t)); new_type->flavor = type->flavor; new_type->flags = type->flags; new_type->s.value = ++state->out->p_types.nprim; if (new_type->s.value > UINT16_MAX) { free(new_id); free(new_type); ERR(state->handle, "type space overflow"); return -1; } new_type->primary = 1; state->typemap[type->s.value - 1] = new_type->s.value; ret = hashtab_insert(state->out->p_types.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_type); if (ret) { free(new_id); free(new_type); ERR(state->handle, "hashtab overflow"); return -1; } if (new_type->flags & TYPE_FLAGS_PERMISSIVE) if (ebitmap_set_bit(&state->out->permissive_map, new_type->s.value, 1)) { ERR(state->handle, "Out of memory!\n"); return -1; } return 0; } static int attr_convert_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id; type_datum_t *type, *new_type; expand_state_t *state; ebitmap_t tmp_union; id = (char *)key; type = (type_datum_t *) datum; state = (expand_state_t *) data; if (type->flavor != TYPE_ATTRIB) return 0; if (!is_id_enabled(id, state->base, SYM_TYPES)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "converting attribute %s", id); new_type = hashtab_search(state->out->p_types.table, id); if (!new_type) { ERR(state->handle, "attribute %s vanished!", id); return -1; } if (map_ebitmap(&type->types, &tmp_union, state->typemap)) { ERR(state->handle, "out of memory"); return -1; } /* then union tmp_union onto &new_type->types */ if (ebitmap_union(&new_type->types, &tmp_union)) { ERR(state->handle, "Out of memory!"); return -1; } ebitmap_destroy(&tmp_union); return 0; } static int perm_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; symtab_t *s; perm_datum_t *perm, *new_perm; id = key; perm = (perm_datum_t *) datum; s = (symtab_t *) data; new_perm = (perm_datum_t *) malloc(sizeof(perm_datum_t)); if (!new_perm) { return -1; } memset(new_perm, 0, sizeof(perm_datum_t)); new_id = strdup(id); if (!new_id) { free(new_perm); return -1; } new_perm->s.value = perm->s.value; s->nprim++; ret = hashtab_insert(s->table, new_id, (hashtab_datum_t *) new_perm); if (ret) { free(new_id); free(new_perm); return -1; } return 0; } static int common_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; common_datum_t *common, *new_common; expand_state_t *state; id = (char *)key; common = (common_datum_t *) datum; state = (expand_state_t *) data; if (state->verbose) INFO(state->handle, "copying common %s", id); new_common = (common_datum_t *) malloc(sizeof(common_datum_t)); if (!new_common) { ERR(state->handle, "Out of memory!"); return -1; } memset(new_common, 0, sizeof(common_datum_t)); if (symtab_init(&new_common->permissions, PERM_SYMTAB_SIZE)) { ERR(state->handle, "Out of memory!"); free(new_common); return -1; } new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); /* free memory created by symtab_init first, then free new_common */ symtab_destroy(&new_common->permissions); free(new_common); return -1; } new_common->s.value = common->s.value; state->out->p_commons.nprim++; ret = hashtab_insert(state->out->p_commons.table, new_id, (hashtab_datum_t *) new_common); if (ret) { ERR(state->handle, "hashtab overflow"); free(new_common); free(new_id); return -1; } if (hashtab_map (common->permissions.table, perm_copy_callback, &new_common->permissions)) { ERR(state->handle, "Out of memory!"); return -1; } return 0; } static int constraint_node_clone(constraint_node_t ** dst, constraint_node_t * src, expand_state_t * state) { constraint_node_t *new_con = NULL, *last_new_con = NULL; constraint_expr_t *new_expr = NULL; *dst = NULL; while (src != NULL) { constraint_expr_t *expr, *expr_l = NULL; new_con = (constraint_node_t *) malloc(sizeof(constraint_node_t)); if (!new_con) { goto out_of_mem; } memset(new_con, 0, sizeof(constraint_node_t)); new_con->permissions = src->permissions; for (expr = src->expr; expr; expr = expr->next) { if ((new_expr = calloc(1, sizeof(*new_expr))) == NULL) { goto out_of_mem; } if (constraint_expr_init(new_expr) == -1) { goto out_of_mem; } new_expr->expr_type = expr->expr_type; new_expr->attr = expr->attr; new_expr->op = expr->op; if (new_expr->expr_type == CEXPR_NAMES) { if (new_expr->attr & CEXPR_TYPE) { /* * Copy over constraint policy source types and/or * attributes for sepol_compute_av_reason_buffer(3) * so that utilities can analyse constraint errors. */ if (map_ebitmap(&expr->type_names->types, &new_expr->type_names->types, state->typemap)) { ERR(NULL, "Failed to map type_names->types"); goto out_of_mem; } /* Type sets require expansion and conversion. */ if (expand_convert_type_set(state->out, state-> typemap, expr-> type_names, &new_expr-> names, 1)) { goto out_of_mem; } } else if (new_expr->attr & CEXPR_ROLE) { if (map_ebitmap(&expr->names, &new_expr->names, state->rolemap)) { goto out_of_mem; } } else if (new_expr->attr & CEXPR_USER) { if (map_ebitmap(&expr->names, &new_expr->names, state->usermap)) { goto out_of_mem; } } else { /* Other kinds of sets do not. */ if (ebitmap_cpy(&new_expr->names, &expr->names)) { goto out_of_mem; } } } if (expr_l) { expr_l->next = new_expr; } else { new_con->expr = new_expr; } expr_l = new_expr; new_expr = NULL; } if (last_new_con == NULL) { *dst = new_con; } else { last_new_con->next = new_con; } last_new_con = new_con; src = src->next; } return 0; out_of_mem: ERR(state->handle, "Out of memory!"); if (new_con) free(new_con); constraint_expr_destroy(new_expr); return -1; } static int class_copy_default_new_object(expand_state_t *state, class_datum_t *olddatum, class_datum_t *newdatum) { if (olddatum->default_user) { if (newdatum->default_user && olddatum->default_user != newdatum->default_user) { ERR(state->handle, "Found conflicting default user definitions"); return SEPOL_ENOTSUP; } newdatum->default_user = olddatum->default_user; } if (olddatum->default_role) { if (newdatum->default_role && olddatum->default_role != newdatum->default_role) { ERR(state->handle, "Found conflicting default role definitions"); return SEPOL_ENOTSUP; } newdatum->default_role = olddatum->default_role; } if (olddatum->default_type) { if (newdatum->default_type && olddatum->default_type != newdatum->default_type) { ERR(state->handle, "Found conflicting default type definitions"); return SEPOL_ENOTSUP; } newdatum->default_type = olddatum->default_type; } if (olddatum->default_range) { if (newdatum->default_range && olddatum->default_range != newdatum->default_range) { ERR(state->handle, "Found conflicting default range definitions"); return SEPOL_ENOTSUP; } newdatum->default_range = olddatum->default_range; } return 0; } static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; class_datum_t *class, *new_class; expand_state_t *state; id = (char *)key; class = (class_datum_t *) datum; state = (expand_state_t *) data; if (!is_id_enabled(id, state->base, SYM_CLASSES)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying class %s", id); new_class = (class_datum_t *) malloc(sizeof(class_datum_t)); if (!new_class) { ERR(state->handle, "Out of memory!"); return -1; } memset(new_class, 0, sizeof(class_datum_t)); if (symtab_init(&new_class->permissions, PERM_SYMTAB_SIZE)) { ERR(state->handle, "Out of memory!"); free(new_class); return -1; } new_class->s.value = class->s.value; state->out->p_classes.nprim++; ret = class_copy_default_new_object(state, class, new_class); if (ret) { free(new_class); return ret; } new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); free(new_class); return -1; } ret = hashtab_insert(state->out->p_classes.table, new_id, (hashtab_datum_t *) new_class); if (ret) { ERR(state->handle, "hashtab overflow"); free(new_class); free(new_id); return -1; } if (hashtab_map (class->permissions.table, perm_copy_callback, &new_class->permissions)) { ERR(state->handle, "hashtab overflow"); return -1; } if (class->comkey) { new_class->comkey = strdup(class->comkey); if (!new_class->comkey) { ERR(state->handle, "Out of memory!"); return -1; } new_class->comdatum = hashtab_search(state->out->p_commons.table, new_class->comkey); if (!new_class->comdatum) { ERR(state->handle, "could not find common datum %s", new_class->comkey); return -1; } new_class->permissions.nprim += new_class->comdatum->permissions.nprim; } return 0; } static int constraint_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id; class_datum_t *class, *new_class; expand_state_t *state; id = (char *)key; class = (class_datum_t *) datum; state = (expand_state_t *) data; new_class = hashtab_search(state->out->p_classes.table, id); if (!new_class) { ERR(state->handle, "class %s vanished", id); return -1; } /* constraints */ if (constraint_node_clone (&new_class->constraints, class->constraints, state) == -1 || constraint_node_clone(&new_class->validatetrans, class->validatetrans, state) == -1) { return -1; } return 0; } /* * The boundaries have to be copied after the types/roles/users are copied, * because it refers hashtab to lookup destinated objects. */ static int type_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { expand_state_t *state = (expand_state_t *) data; type_datum_t *type = (type_datum_t *) datum; type_datum_t *dest; uint32_t bounds_val; if (!type->bounds) return 0; if (!is_id_enabled((char *)key, state->base, SYM_TYPES)) return 0; bounds_val = state->typemap[type->bounds - 1]; dest = hashtab_search(state->out->p_types.table, (char *)key); if (!dest) { ERR(state->handle, "Type lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } static int role_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { expand_state_t *state = (expand_state_t *) data; role_datum_t *role = (role_datum_t *) datum; role_datum_t *dest; uint32_t bounds_val; if (!role->bounds) return 0; if (!is_id_enabled((char *)key, state->base, SYM_ROLES)) return 0; bounds_val = state->rolemap[role->bounds - 1]; dest = hashtab_search(state->out->p_roles.table, (char *)key); if (!dest) { ERR(state->handle, "Role lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } static int user_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { expand_state_t *state = (expand_state_t *) data; user_datum_t *user = (user_datum_t *) datum; user_datum_t *dest; uint32_t bounds_val; if (!user->bounds) return 0; if (!is_id_enabled((char *)key, state->base, SYM_USERS)) return 0; bounds_val = state->usermap[user->bounds - 1]; dest = hashtab_search(state->out->p_users.table, (char *)key); if (!dest) { ERR(state->handle, "User lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } /* The aliases have to be copied after the types and attributes to be certain that * the out symbol table will have the type that the alias refers. Otherwise, we * won't be able to find the type value for the alias. We can't depend on the * declaration ordering because of the hash table. */ static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; type_datum_t *alias, *new_alias; expand_state_t *state; uint32_t prival; id = (char *)key; alias = (type_datum_t *) datum; state = (expand_state_t *) data; /* ignore regular types */ if (alias->flavor == TYPE_TYPE && alias->primary) return 0; /* ignore attributes */ if (alias->flavor == TYPE_ATTRIB) return 0; if (alias->flavor == TYPE_ALIAS) prival = alias->primary; else prival = alias->s.value; if (!is_id_enabled(state->base->p_type_val_to_name[prival - 1], state->base, SYM_TYPES)) { /* The primary type for this alias is not enabled, the alias * shouldn't be either */ return 0; } if (state->verbose) INFO(state->handle, "copying alias %s", id); new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); return -1; } new_alias = (type_datum_t *) malloc(sizeof(type_datum_t)); if (!new_alias) { ERR(state->handle, "Out of memory!"); free(new_id); return SEPOL_ENOMEM; } memset(new_alias, 0, sizeof(type_datum_t)); if (alias->flavor == TYPE_TYPE) new_alias->s.value = state->typemap[alias->s.value - 1]; else if (alias->flavor == TYPE_ALIAS) new_alias->s.value = state->typemap[alias->primary - 1]; else assert(0); /* unreachable */ new_alias->flags = alias->flags; ret = hashtab_insert(state->out->p_types.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_alias); if (ret) { ERR(state->handle, "hashtab overflow"); free(new_alias); free(new_id); return -1; } state->typemap[alias->s.value - 1] = new_alias->s.value; if (new_alias->flags & TYPE_FLAGS_PERMISSIVE) if (ebitmap_set_bit(&state->out->permissive_map, new_alias->s.value, 1)) { ERR(state->handle, "Out of memory!"); return -1; } return 0; } static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *data) { ebitmap_t mapped_roles; role_datum_t *role = (role_datum_t *) datum; expand_state_t *state = (expand_state_t *) data; if (map_ebitmap(&role->dominates, &mapped_roles, state->rolemap)) return -1; ebitmap_destroy(&role->dominates); if (ebitmap_cpy(&role->dominates, &mapped_roles)) return -1; ebitmap_destroy(&mapped_roles); return 0; } /* For the role attribute in the base module, escalate its counterpart's * types.types ebitmap in the out module to the counterparts of all the * regular role that belongs to the current role attribute. Note, must be * invoked after role_copy_callback so that state->rolemap is available. */ static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id, *base_reg_role_id; role_datum_t *role, *new_role, *regular_role; expand_state_t *state; ebitmap_node_t *rnode; unsigned int i; ebitmap_t mapped_roles; id = key; role = (role_datum_t *)datum; state = (expand_state_t *)data; if (strcmp(id, OBJECT_R) == 0) { /* object_r is never a role attribute by far */ return 0; } if (!is_id_enabled(id, state->base, SYM_ROLES)) { /* identifier's scope is not enabled */ return 0; } if (role->flavor != ROLE_ATTRIB) return 0; if (state->verbose) INFO(state->handle, "fixing role attribute %s", id); new_role = (role_datum_t *)hashtab_search(state->out->p_roles.table, id); assert(new_role != NULL && new_role->flavor == ROLE_ATTRIB); ebitmap_init(&mapped_roles); if (map_ebitmap(&role->roles, &mapped_roles, state->rolemap)) return -1; if (ebitmap_union(&new_role->roles, &mapped_roles)) { ERR(state->handle, "Out of memory!"); ebitmap_destroy(&mapped_roles); return -1; } ebitmap_destroy(&mapped_roles); ebitmap_for_each_bit(&role->roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { /* take advantage of sym_val_to_name[] * of the base module */ base_reg_role_id = state->base->p_role_val_to_name[i]; regular_role = (role_datum_t *)hashtab_search( state->out->p_roles.table, base_reg_role_id); assert(regular_role != NULL && regular_role->flavor == ROLE_ROLE); if (ebitmap_union(®ular_role->types.types, &new_role->types.types)) { ERR(state->handle, "Out of memory!"); return -1; } } } return 0; } static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id, *new_id; role_datum_t *role; role_datum_t *new_role; expand_state_t *state; ebitmap_t tmp_union_types; id = key; role = (role_datum_t *) datum; state = (expand_state_t *) data; if (strcmp(id, OBJECT_R) == 0) { /* object_r is always value 1 */ state->rolemap[role->s.value - 1] = 1; return 0; } if (!is_id_enabled(id, state->base, SYM_ROLES)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying role %s", id); new_role = (role_datum_t *) hashtab_search(state->out->p_roles.table, id); if (!new_role) { new_role = (role_datum_t *) malloc(sizeof(role_datum_t)); if (!new_role) { ERR(state->handle, "Out of memory!"); return -1; } memset(new_role, 0, sizeof(role_datum_t)); new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); free(new_role); return -1; } state->out->p_roles.nprim++; new_role->flavor = role->flavor; new_role->s.value = state->out->p_roles.nprim; state->rolemap[role->s.value - 1] = new_role->s.value; ret = hashtab_insert(state->out->p_roles.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_role); if (ret) { ERR(state->handle, "hashtab overflow"); free(new_role); free(new_id); return -1; } } /* The dominates bitmap is going to be wrong for the moment, * we'll come back later and remap them, after we are sure all * the roles have been added */ if (ebitmap_union(&new_role->dominates, &role->dominates)) { ERR(state->handle, "Out of memory!"); return -1; } ebitmap_init(&tmp_union_types); /* convert types in the role datum in the global symtab */ if (expand_convert_type_set (state->out, state->typemap, &role->types, &tmp_union_types, 1)) { ebitmap_destroy(&tmp_union_types); ERR(state->handle, "Out of memory!"); return -1; } if (ebitmap_union(&new_role->types.types, &tmp_union_types)) { ERR(state->handle, "Out of memory!"); ebitmap_destroy(&tmp_union_types); return -1; } ebitmap_destroy(&tmp_union_types); return 0; } int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, policydb_t * p, sepol_handle_t * h) { mls_semantic_cat_t *cat; level_datum_t *levdatum; unsigned int i; mls_level_init(l); if (!p->mls) return 0; /* Required not declared. */ if (!sl->sens) return 0; l->sens = sl->sens; levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, p->p_sens_val_to_name[l->sens - 1]); if (!levdatum) { ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n", __func__); errno = ENOENT; return -1; } for (cat = sl->cat; cat; cat = cat->next) { if (cat->low > cat->high) { ERR(h, "Category range is not valid %s.%s", p->p_cat_val_to_name[cat->low - 1], p->p_cat_val_to_name[cat->high - 1]); return -1; } for (i = cat->low - 1; i < cat->high; i++) { if (!ebitmap_get_bit(&levdatum->level->cat, i)) { ERR(h, "Category %s can not be associate with " "level %s", p->p_cat_val_to_name[i], p->p_sens_val_to_name[l->sens - 1]); } if (ebitmap_set_bit(&l->cat, i, 1)) { ERR(h, "Out of memory!"); return -1; } } } return 0; } int mls_semantic_range_expand(mls_semantic_range_t * sr, mls_range_t * r, policydb_t * p, sepol_handle_t * h) { if (mls_semantic_level_expand(&sr->level[0], &r->level[0], p, h) < 0) return -1; if (mls_semantic_level_expand(&sr->level[1], &r->level[1], p, h) < 0) { mls_semantic_level_destroy(&sr->level[0]); return -1; } if (!mls_level_dom(&r->level[1], &r->level[0])) { mls_range_destroy(r); ERR(h, "MLS range high level does not dominate low level"); return -1; } return 0; } static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; expand_state_t *state; user_datum_t *user; user_datum_t *new_user; char *id, *new_id; ebitmap_t tmp_union; id = key; user = (user_datum_t *) datum; state = (expand_state_t *) data; if (!is_id_enabled(id, state->base, SYM_USERS)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying user %s", id); new_user = (user_datum_t *) hashtab_search(state->out->p_users.table, id); if (!new_user) { new_user = (user_datum_t *) malloc(sizeof(user_datum_t)); if (!new_user) { ERR(state->handle, "Out of memory!"); return -1; } memset(new_user, 0, sizeof(user_datum_t)); state->out->p_users.nprim++; new_user->s.value = state->out->p_users.nprim; state->usermap[user->s.value - 1] = new_user->s.value; new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); free(new_user); return -1; } ret = hashtab_insert(state->out->p_users.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_user); if (ret) { ERR(state->handle, "hashtab overflow"); user_datum_destroy(new_user); free(new_user); free(new_id); return -1; } /* expand the semantic MLS info */ if (mls_semantic_range_expand(&user->range, &new_user->exp_range, state->out, state->handle)) { return -1; } if (mls_semantic_level_expand(&user->dfltlevel, &new_user->exp_dfltlevel, state->out, state->handle)) { return -1; } if (!mls_level_between(&new_user->exp_dfltlevel, &new_user->exp_range.level[0], &new_user->exp_range.level[1])) { ERR(state->handle, "default level not within user " "range"); return -1; } } else { /* require that the MLS info match */ mls_range_t tmp_range; mls_level_t tmp_level; if (mls_semantic_range_expand(&user->range, &tmp_range, state->out, state->handle)) { return -1; } if (mls_semantic_level_expand(&user->dfltlevel, &tmp_level, state->out, state->handle)) { mls_range_destroy(&tmp_range); return -1; } if (!mls_range_eq(&new_user->exp_range, &tmp_range) || !mls_level_eq(&new_user->exp_dfltlevel, &tmp_level)) { mls_range_destroy(&tmp_range); mls_level_destroy(&tmp_level); return -1; } mls_range_destroy(&tmp_range); mls_level_destroy(&tmp_level); } ebitmap_init(&tmp_union); /* get global roles for this user */ if (role_set_expand(&user->roles, &tmp_union, state->out, state->base, state->rolemap)) { ERR(state->handle, "Out of memory!"); ebitmap_destroy(&tmp_union); return -1; } if (ebitmap_union(&new_user->roles.roles, &tmp_union)) { ERR(state->handle, "Out of memory!"); ebitmap_destroy(&tmp_union); return -1; } ebitmap_destroy(&tmp_union); return 0; } static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; expand_state_t *state; cond_bool_datum_t *bool, *new_bool; char *id, *new_id; id = key; bool = (cond_bool_datum_t *) datum; state = (expand_state_t *) data; if (!is_id_enabled(id, state->base, SYM_BOOLS)) { /* identifier's scope is not enabled */ return 0; } if (bool->flags & COND_BOOL_FLAGS_TUNABLE) { /* Skip tunables */ return 0; } if (state->verbose) INFO(state->handle, "copying boolean %s", id); new_bool = (cond_bool_datum_t *) malloc(sizeof(cond_bool_datum_t)); if (!new_bool) { ERR(state->handle, "Out of memory!"); return -1; } new_id = strdup(id); if (!new_id) { ERR(state->handle, "Out of memory!"); free(new_bool); return -1; } state->out->p_bools.nprim++; new_bool->s.value = state->out->p_bools.nprim; ret = hashtab_insert(state->out->p_bools.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_bool); if (ret) { ERR(state->handle, "hashtab overflow"); free(new_bool); free(new_id); return -1; } state->boolmap[bool->s.value - 1] = new_bool->s.value; new_bool->state = bool->state; new_bool->flags = bool->flags; return 0; } static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { expand_state_t *state = (expand_state_t *) data; level_datum_t *level = (level_datum_t *) datum, *new_level = NULL; char *id = (char *)key, *new_id = NULL; if (!is_id_enabled(id, state->base, SYM_LEVELS)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying sensitivity level %s", id); new_level = (level_datum_t *) malloc(sizeof(level_datum_t)); if (!new_level) goto out_of_mem; level_datum_init(new_level); new_level->level = (mls_level_t *) malloc(sizeof(mls_level_t)); if (!new_level->level) goto out_of_mem; mls_level_init(new_level->level); new_id = strdup(id); if (!new_id) goto out_of_mem; if (mls_level_cpy(new_level->level, level->level)) { goto out_of_mem; } new_level->isalias = level->isalias; state->out->p_levels.nprim++; if (hashtab_insert(state->out->p_levels.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_level)) { goto out_of_mem; } return 0; out_of_mem: ERR(state->handle, "Out of memory!"); if (new_level != NULL && new_level->level != NULL) { mls_level_destroy(new_level->level); free(new_level->level); } level_datum_destroy(new_level); free(new_level); free(new_id); return -1; } static int cats_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { expand_state_t *state = (expand_state_t *) data; cat_datum_t *cat = (cat_datum_t *) datum, *new_cat = NULL; char *id = (char *)key, *new_id = NULL; if (!is_id_enabled(id, state->base, SYM_CATS)) { /* identifier's scope is not enabled */ return 0; } if (state->verbose) INFO(state->handle, "copying category attribute %s", id); new_cat = (cat_datum_t *) malloc(sizeof(cat_datum_t)); if (!new_cat) goto out_of_mem; cat_datum_init(new_cat); new_id = strdup(id); if (!new_id) goto out_of_mem; new_cat->s.value = cat->s.value; new_cat->isalias = cat->isalias; state->out->p_cats.nprim++; if (hashtab_insert(state->out->p_cats.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_cat)) { goto out_of_mem; } return 0; out_of_mem: ERR(state->handle, "Out of memory!"); cat_datum_destroy(new_cat); free(new_cat); free(new_id); return -1; } static int copy_role_allows(expand_state_t * state, role_allow_rule_t * rules) { unsigned int i, j; role_allow_t *cur_allow, *n, *l; role_allow_rule_t *cur; ebitmap_t roles, new_roles; ebitmap_node_t *snode, *tnode; /* start at the end of the list */ for (l = state->out->role_allow; l && l->next; l = l->next) ; cur = rules; while (cur) { ebitmap_init(&roles); ebitmap_init(&new_roles); if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) { ERR(state->handle, "Out of memory!"); return -1; } if (role_set_expand(&cur->new_roles, &new_roles, state->out, state->base, state->rolemap)) { ERR(state->handle, "Out of memory!"); return -1; } ebitmap_for_each_bit(&roles, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; ebitmap_for_each_bit(&new_roles, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; /* check for duplicates */ cur_allow = state->out->role_allow; while (cur_allow) { if ((cur_allow->role == i + 1) && (cur_allow->new_role == j + 1)) break; cur_allow = cur_allow->next; } if (cur_allow) continue; n = (role_allow_t *) malloc(sizeof(role_allow_t)); if (!n) { ERR(state->handle, "Out of memory!"); return -1; } memset(n, 0, sizeof(role_allow_t)); n->role = i + 1; n->new_role = j + 1; if (l) { l->next = n; } else { state->out->role_allow = n; } l = n; } } ebitmap_destroy(&roles); ebitmap_destroy(&new_roles); cur = cur->next; } return 0; } static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) { unsigned int i, j, k; role_trans_t *n, *l, *cur_trans; role_trans_rule_t *cur; ebitmap_t roles, types; ebitmap_node_t *rnode, *tnode, *cnode; /* start at the end of the list */ for (l = state->out->role_tr; l && l->next; l = l->next) ; cur = rules; while (cur) { ebitmap_init(&roles); ebitmap_init(&types); if (role_set_expand(&cur->roles, &roles, state->out, state->base, state->rolemap)) { ERR(state->handle, "Out of memory!"); return -1; } if (expand_convert_type_set (state->out, state->typemap, &cur->types, &types, 1)) { ERR(state->handle, "Out of memory!"); return -1; } ebitmap_for_each_bit(&roles, rnode, i) { if (!ebitmap_node_get_bit(rnode, i)) continue; ebitmap_for_each_bit(&types, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; ebitmap_for_each_bit(&cur->classes, cnode, k) { if (!ebitmap_node_get_bit(cnode, k)) continue; cur_trans = state->out->role_tr; while (cur_trans) { unsigned int mapped_role; mapped_role = state->rolemap[cur->new_role - 1]; if ((cur_trans->role == i + 1) && (cur_trans->type == j + 1) && (cur_trans->tclass == k + 1)) { if (cur_trans->new_role == mapped_role) { break; } else { ERR(state->handle, "Conflicting role trans rule %s %s : %s { %s vs %s }", state->out->p_role_val_to_name[i], state->out->p_type_val_to_name[j], state->out->p_class_val_to_name[k], state->out->p_role_val_to_name[mapped_role - 1], state->out->p_role_val_to_name[cur_trans->new_role - 1]); return -1; } } cur_trans = cur_trans->next; } if (cur_trans) continue; n = (role_trans_t *) malloc(sizeof(role_trans_t)); if (!n) { ERR(state->handle, "Out of memory!"); return -1; } memset(n, 0, sizeof(role_trans_t)); n->role = i + 1; n->type = j + 1; n->tclass = k + 1; n->new_role = state->rolemap [cur->new_role - 1]; if (l) l->next = n; else state->out->role_tr = n; l = n; } } } ebitmap_destroy(&roles); ebitmap_destroy(&types); cur = cur->next; } return 0; } static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) { unsigned int i, j; filename_trans_t *new_trans, *cur_trans, *end; filename_trans_rule_t *cur_rule; ebitmap_t stypes, ttypes; ebitmap_node_t *snode, *tnode; struct linear_probe probe; /* * Linear probing speeds-up finding filename_trans rules with certain * "stype" value. */ if (linear_probe_create(&probe, 4096)) { /* Assume 4096 is enough for most cases */ ERR(state->handle, "Out of memory!"); return -1; } cur_rule = rules; while (cur_rule) { uint32_t mapped_otype; ebitmap_init(&stypes); ebitmap_init(&ttypes); if (expand_convert_type_set(state->out, state->typemap, &cur_rule->stypes, &stypes, 1)) { ERR(state->handle, "Out of memory!"); return -1; } if (expand_convert_type_set(state->out, state->typemap, &cur_rule->ttypes, &ttypes, 1)) { ERR(state->handle, "Out of memory!"); return -1; } mapped_otype = state->typemap[cur_rule->otype - 1]; if (ebitmap_length(&stypes) > probe.length) { linear_probe_destroy(&probe); if (linear_probe_create(&probe, ebitmap_length(&stypes))) { ERR(state->handle, "Out of memory!"); return -1; } } ebitmap_for_each_bit(&stypes, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; ebitmap_for_each_bit(&ttypes, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; cur_trans = linear_probe_find(&probe, i); while (cur_trans != NULL) { if ((cur_trans->ttype == j + 1) && (cur_trans->tclass == cur_rule->tclass) && (!strcmp(cur_trans->name, cur_rule->name))) { /* duplicate rule, who cares */ if (cur_trans->otype == mapped_otype) break; ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s", cur_trans->name, state->out->p_type_val_to_name[i], state->out->p_type_val_to_name[j], state->out->p_class_val_to_name[cur_trans->tclass - 1], state->out->p_type_val_to_name[cur_trans->otype - 1], state->out->p_type_val_to_name[mapped_otype - 1]); return -1; } cur_trans = cur_trans->next; } /* duplicate rule, who cares */ if (cur_trans) continue; new_trans = malloc(sizeof(*new_trans)); if (!new_trans) { ERR(state->handle, "Out of memory!"); return -1; } memset(new_trans, 0, sizeof(*new_trans)); new_trans->name = strdup(cur_rule->name); if (!new_trans->name) { ERR(state->handle, "Out of memory!"); return -1; } new_trans->stype = i + 1; new_trans->ttype = j + 1; new_trans->tclass = cur_rule->tclass; new_trans->otype = mapped_otype; linear_probe_insert(&probe, i, new_trans); } } cur_trans = linear_probe_dump(&probe, &end); if (cur_trans != NULL) { end->next = state->out->filename_trans; state->out->filename_trans = cur_trans; } ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); cur_rule = cur_rule->next; } return 0; } static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass, mls_semantic_range_t * trange, expand_state_t * state) { range_trans_t *rt, *check_rt = state->out->range_tr; mls_range_t exp_range; int rc = -1; if (mls_semantic_range_expand(trange, &exp_range, state->out, state->handle)) goto out; /* check for duplicates/conflicts */ while (check_rt) { if ((check_rt->source_type == stype) && (check_rt->target_type == ttype) && (check_rt->target_class == tclass)) { if (mls_range_eq(&check_rt->target_range, &exp_range)) { /* duplicate */ break; } else { /* conflict */ ERR(state->handle, "Conflicting range trans rule %s %s : %s", state->out->p_type_val_to_name[stype - 1], state->out->p_type_val_to_name[ttype - 1], state->out->p_class_val_to_name[tclass - 1]); goto out; } } check_rt = check_rt->next; } if (check_rt) { /* this is a dup - skip */ rc = 0; goto out; } rt = (range_trans_t *) calloc(1, sizeof(range_trans_t)); if (!rt) { ERR(state->handle, "Out of memory!"); goto out; } rt->next = state->out->range_tr; state->out->range_tr = rt; rt->source_type = stype; rt->target_type = ttype; rt->target_class = tclass; if (mls_range_cpy(&rt->target_range, &exp_range)) { ERR(state->handle, "Out of memory!"); goto out; } rc = 0; out: mls_range_destroy(&exp_range); return rc; } static int expand_range_trans(expand_state_t * state, range_trans_rule_t * rules) { unsigned int i, j, k; range_trans_rule_t *rule; ebitmap_t stypes, ttypes; ebitmap_node_t *snode, *tnode, *cnode; if (state->verbose) INFO(state->handle, "expanding range transitions"); for (rule = rules; rule; rule = rule->next) { ebitmap_init(&stypes); ebitmap_init(&ttypes); /* expand the type sets */ if (expand_convert_type_set(state->out, state->typemap, &rule->stypes, &stypes, 1)) { ERR(state->handle, "Out of memory!"); return -1; } if (expand_convert_type_set(state->out, state->typemap, &rule->ttypes, &ttypes, 1)) { ebitmap_destroy(&stypes); ERR(state->handle, "Out of memory!"); return -1; } /* loop on source type */ ebitmap_for_each_bit(&stypes, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; /* loop on target type */ ebitmap_for_each_bit(&ttypes, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; /* loop on target class */ ebitmap_for_each_bit(&rule->tclasses, cnode, k) { if (!ebitmap_node_get_bit(cnode, k)) continue; if (exp_rangetr_helper(i + 1, j + 1, k + 1, &rule->trange, state)) { ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); return -1; } } } } ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); } return 0; } /* Search for an AV tab node within a hash table with the given key. * If the node does not exist, create it and return it; otherwise * return the pre-existing one. */ static avtab_ptr_t find_avtab_node(sepol_handle_t * handle, avtab_t * avtab, avtab_key_t * key, cond_av_list_t ** cond) { avtab_ptr_t node; avtab_datum_t avdatum; cond_av_list_t *nl; node = avtab_search_node(avtab, key); /* If this is for conditional policies, keep searching in case the node is part of my conditional avtab. */ if (cond) { while (node) { if (node->parse_context == cond) break; node = avtab_search_node_next(node, key->specified); } } if (!node) { memset(&avdatum, 0, sizeof avdatum); /* this is used to get the node - insertion is actually unique */ node = avtab_insert_nonunique(avtab, key, &avdatum); if (!node) { ERR(handle, "hash table overflow"); return NULL; } if (cond) { node->parse_context = cond; nl = (cond_av_list_t *) malloc(sizeof(cond_av_list_t)); if (!nl) { ERR(handle, "Memory error"); return NULL; } memset(nl, 0, sizeof(cond_av_list_t)); nl->node = node; nl->next = *cond; *cond = nl; } } return node; } #define EXPAND_RULE_SUCCESS 1 #define EXPAND_RULE_CONFLICT 0 #define EXPAND_RULE_ERROR -1 static int expand_terule_helper(sepol_handle_t * handle, policydb_t * p, uint32_t * typemap, uint32_t specified, cond_av_list_t ** cond, cond_av_list_t ** other, uint32_t stype, uint32_t ttype, class_perm_node_t * perms, avtab_t * avtab, int enabled) { avtab_key_t avkey; avtab_datum_t *avdatump; avtab_ptr_t node; class_perm_node_t *cur; int conflict; uint32_t oldtype = 0, spec = 0; if (specified & AVRULE_TRANSITION) { spec = AVTAB_TRANSITION; } else if (specified & AVRULE_MEMBER) { spec = AVTAB_MEMBER; } else if (specified & AVRULE_CHANGE) { spec = AVTAB_CHANGE; } else { assert(0); /* unreachable */ } cur = perms; while (cur) { uint32_t remapped_data = typemap ? typemap[cur->data - 1] : cur->data; avkey.source_type = stype + 1; avkey.target_type = ttype + 1; avkey.target_class = cur->class; avkey.specified = spec; conflict = 0; /* check to see if the expanded TE already exists -- * either in the global scope or in another * conditional AV tab */ node = avtab_search_node(&p->te_avtab, &avkey); if (node) { conflict = 1; } else { node = avtab_search_node(&p->te_cond_avtab, &avkey); if (node && node->parse_context != other) { conflict = 2; } } if (conflict) { avdatump = &node->datum; if (specified & AVRULE_TRANSITION) { oldtype = avdatump->data; } else if (specified & AVRULE_MEMBER) { oldtype = avdatump->data; } else if (specified & AVRULE_CHANGE) { oldtype = avdatump->data; } if (oldtype == remapped_data) { /* if the duplicate is inside the same scope (eg., unconditional * or in same conditional then ignore it */ if ((conflict == 1 && cond == NULL) || node->parse_context == cond) return EXPAND_RULE_SUCCESS; ERR(handle, "duplicate TE rule for %s %s:%s %s", p->p_type_val_to_name[avkey.source_type - 1], p->p_type_val_to_name[avkey.target_type - 1], p->p_class_val_to_name[avkey.target_class - 1], p->p_type_val_to_name[oldtype - 1]); return EXPAND_RULE_CONFLICT; } ERR(handle, "conflicting TE rule for (%s, %s:%s): old was %s, new is %s", p->p_type_val_to_name[avkey.source_type - 1], p->p_type_val_to_name[avkey.target_type - 1], p->p_class_val_to_name[avkey.target_class - 1], p->p_type_val_to_name[oldtype - 1], p->p_type_val_to_name[remapped_data - 1]); return EXPAND_RULE_CONFLICT; } node = find_avtab_node(handle, avtab, &avkey, cond); if (!node) return -1; if (enabled) { node->key.specified |= AVTAB_ENABLED; } else { node->key.specified &= ~AVTAB_ENABLED; } avdatump = &node->datum; if (specified & AVRULE_TRANSITION) { avdatump->data = remapped_data; } else if (specified & AVRULE_MEMBER) { avdatump->data = remapped_data; } else if (specified & AVRULE_CHANGE) { avdatump->data = remapped_data; } else { assert(0); /* should never occur */ } cur = cur->next; } return EXPAND_RULE_SUCCESS; } static int expand_avrule_helper(sepol_handle_t * handle, uint32_t specified, cond_av_list_t ** cond, uint32_t stype, uint32_t ttype, class_perm_node_t * perms, avtab_t * avtab, int enabled) { avtab_key_t avkey; avtab_datum_t *avdatump; avtab_ptr_t node; class_perm_node_t *cur; uint32_t spec = 0; if (specified & AVRULE_ALLOWED) { spec = AVTAB_ALLOWED; } else if (specified & AVRULE_AUDITALLOW) { spec = AVTAB_AUDITALLOW; } else if (specified & AVRULE_AUDITDENY) { spec = AVTAB_AUDITDENY; } else if (specified & AVRULE_DONTAUDIT) { if (handle && handle->disable_dontaudit) return EXPAND_RULE_SUCCESS; spec = AVTAB_AUDITDENY; } else if (specified & AVRULE_NEVERALLOW) { spec = AVTAB_NEVERALLOW; } else { assert(0); /* unreachable */ } cur = perms; while (cur) { avkey.source_type = stype + 1; avkey.target_type = ttype + 1; avkey.target_class = cur->class; avkey.specified = spec; node = find_avtab_node(handle, avtab, &avkey, cond); if (!node) return EXPAND_RULE_ERROR; if (enabled) { node->key.specified |= AVTAB_ENABLED; } else { node->key.specified &= ~AVTAB_ENABLED; } avdatump = &node->datum; if (specified & AVRULE_ALLOWED) { avdatump->data |= cur->data; } else if (specified & AVRULE_AUDITALLOW) { avdatump->data |= cur->data; } else if (specified & AVRULE_NEVERALLOW) { avdatump->data |= cur->data; } else if (specified & AVRULE_AUDITDENY) { /* Since a '0' in an auditdeny mask represents * a permission we do NOT want to audit * (dontaudit), we use the '&' operand to * ensure that all '0's in the mask are * retained (much unlike the allow and * auditallow cases). */ avdatump->data &= cur->data; } else if (specified & AVRULE_DONTAUDIT) { if (avdatump->data) avdatump->data &= ~cur->data; else avdatump->data = ~cur->data; } else { assert(0); /* should never occur */ } cur = cur->next; } return EXPAND_RULE_SUCCESS; } static int expand_rule_helper(sepol_handle_t * handle, policydb_t * p, uint32_t * typemap, avrule_t * source_rule, avtab_t * dest_avtab, cond_av_list_t ** cond, cond_av_list_t ** other, int enabled, ebitmap_t * stypes, ebitmap_t * ttypes) { unsigned int i, j; int retval; ebitmap_node_t *snode, *tnode; ebitmap_for_each_bit(stypes, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; if (source_rule->flags & RULE_SELF) { if (source_rule->specified & AVRULE_AV) { retval = expand_avrule_helper(handle, source_rule->specified, cond, i, i, source_rule->perms, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; } else { retval = expand_terule_helper(handle, p, typemap, source_rule->specified, cond, other, i, i, source_rule->perms, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; } } ebitmap_for_each_bit(ttypes, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; if (source_rule->specified & AVRULE_AV) { retval = expand_avrule_helper(handle, source_rule->specified, cond, i, j, source_rule->perms, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; } else { retval = expand_terule_helper(handle, p, typemap, source_rule->specified, cond, other, i, j, source_rule->perms, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; } } } return EXPAND_RULE_SUCCESS; } /* * Expand a rule into a given avtab - checking for conflicting type * rules in the destination policy. Return EXPAND_RULE_SUCCESS on * success, EXPAND_RULE_CONFLICT if the rule conflicts with something * (and hence was not added), or EXPAND_RULE_ERROR on error. */ static int convert_and_expand_rule(sepol_handle_t * handle, policydb_t * dest_pol, uint32_t * typemap, avrule_t * source_rule, avtab_t * dest_avtab, cond_av_list_t ** cond, cond_av_list_t ** other, int enabled, int do_neverallow) { int retval; ebitmap_t stypes, ttypes; unsigned char alwaysexpand; if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW) return EXPAND_RULE_SUCCESS; ebitmap_init(&stypes); ebitmap_init(&ttypes); /* Force expansion for type rules and for self rules. */ alwaysexpand = ((source_rule->specified & AVRULE_TYPE) || (source_rule->flags & RULE_SELF)); if (expand_convert_type_set (dest_pol, typemap, &source_rule->stypes, &stypes, alwaysexpand)) return EXPAND_RULE_ERROR; if (expand_convert_type_set (dest_pol, typemap, &source_rule->ttypes, &ttypes, alwaysexpand)) return EXPAND_RULE_ERROR; retval = expand_rule_helper(handle, dest_pol, typemap, source_rule, dest_avtab, cond, other, enabled, &stypes, &ttypes); ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); return retval; } static int cond_avrule_list_copy(policydb_t * dest_pol, avrule_t * source_rules, avtab_t * dest_avtab, cond_av_list_t ** list, cond_av_list_t ** other, uint32_t * typemap, int enabled, expand_state_t * state) { avrule_t *cur; cur = source_rules; while (cur) { if (convert_and_expand_rule(state->handle, dest_pol, typemap, cur, dest_avtab, list, other, enabled, 0) != EXPAND_RULE_SUCCESS) { return -1; } cur = cur->next; } return 0; } static int cond_node_map_bools(expand_state_t * state, cond_node_t * cn) { cond_expr_t *cur; unsigned int i; cur = cn->expr; while (cur) { if (cur->bool) cur->bool = state->boolmap[cur->bool - 1]; cur = cur->next; } for (i = 0; i < min(cn->nbools, COND_MAX_BOOLS); i++) cn->bool_ids[i] = state->boolmap[cn->bool_ids[i] - 1]; if (cond_normalize_expr(state->out, cn)) { ERR(state->handle, "Error while normalizing conditional"); return -1; } return 0; } /* copy the nodes in *reverse* order -- the result is that the last * given conditional appears first in the policy, so as to match the * behavior of the upstream compiler */ static int cond_node_copy(expand_state_t * state, cond_node_t * cn) { cond_node_t *new_cond, *tmp; if (cn == NULL) { return 0; } if (cond_node_copy(state, cn->next)) { return -1; } /* If current cond_node_t is of tunable, its effective branch * has been appended to its home decl->avrules list during link * and now we should just skip it. */ if (cn->flags & COND_NODE_FLAGS_TUNABLE) return 0; if (cond_normalize_expr(state->base, cn)) { ERR(state->handle, "Error while normalizing conditional"); return -1; } /* create a new temporary conditional node with the booleans * mapped */ tmp = cond_node_create(state->base, cn); if (!tmp) { ERR(state->handle, "Out of memory"); return -1; } if (cond_node_map_bools(state, tmp)) { cond_node_destroy(tmp); free(tmp); ERR(state->handle, "Error mapping booleans"); return -1; } new_cond = cond_node_search(state->out, state->out->cond_list, tmp); if (!new_cond) { cond_node_destroy(tmp); free(tmp); ERR(state->handle, "Out of memory!"); return -1; } cond_node_destroy(tmp); free(tmp); if (cond_avrule_list_copy (state->out, cn->avtrue_list, &state->out->te_cond_avtab, &new_cond->true_list, &new_cond->false_list, state->typemap, new_cond->cur_state, state)) return -1; if (cond_avrule_list_copy (state->out, cn->avfalse_list, &state->out->te_cond_avtab, &new_cond->false_list, &new_cond->true_list, state->typemap, !new_cond->cur_state, state)) return -1; return 0; } static int context_copy(context_struct_t * dst, context_struct_t * src, expand_state_t * state) { dst->user = state->usermap[src->user - 1]; dst->role = state->rolemap[src->role - 1]; dst->type = state->typemap[src->type - 1]; return mls_context_cpy(dst, src); } static int ocontext_copy_xen(expand_state_t *state) { unsigned int i; ocontext_t *c, *n, *l; for (i = 0; i < OCON_NUM; i++) { l = NULL; for (c = state->base->ocontexts[i]; c; c = c->next) { n = malloc(sizeof(ocontext_t)); if (!n) { ERR(state->handle, "Out of memory!"); return -1; } memset(n, 0, sizeof(ocontext_t)); if (l) l->next = n; else state->out->ocontexts[i] = n; l = n; switch (i) { case OCON_XEN_ISID: if (c->context[0].user == 0) { ERR(state->handle, "Missing context for %s initial sid", c->u.name); return -1; } n->sid[0] = c->sid[0]; break; case OCON_XEN_PIRQ: n->u.pirq = c->u.pirq; break; case OCON_XEN_IOPORT: n->u.ioport.low_ioport = c->u.ioport.low_ioport; n->u.ioport.high_ioport = c->u.ioport.high_ioport; break; case OCON_XEN_IOMEM: n->u.iomem.low_iomem = c->u.iomem.low_iomem; n->u.iomem.high_iomem = c->u.iomem.high_iomem; break; case OCON_XEN_PCIDEVICE: n->u.device = c->u.device; break; default: /* shouldn't get here */ ERR(state->handle, "Unknown ocontext"); return -1; } if (context_copy(&n->context[0], &c->context[0], state)) { ERR(state->handle, "Out of memory!"); return -1; } } } return 0; } static int ocontext_copy_selinux(expand_state_t *state) { unsigned int i, j; ocontext_t *c, *n, *l; for (i = 0; i < OCON_NUM; i++) { l = NULL; for (c = state->base->ocontexts[i]; c; c = c->next) { n = malloc(sizeof(ocontext_t)); if (!n) { ERR(state->handle, "Out of memory!"); return -1; } memset(n, 0, sizeof(ocontext_t)); if (l) l->next = n; else state->out->ocontexts[i] = n; l = n; switch (i) { case OCON_ISID: if (c->context[0].user == 0) { ERR(state->handle, "Missing context for %s initial sid", c->u.name); return -1; } n->sid[0] = c->sid[0]; break; case OCON_FS: /* FALLTHROUGH */ case OCON_NETIF: n->u.name = strdup(c->u.name); if (!n->u.name) { ERR(state->handle, "Out of memory!"); return -1; } if (context_copy (&n->context[1], &c->context[1], state)) { ERR(state->handle, "Out of memory!"); return -1; } break; case OCON_PORT: n->u.port.protocol = c->u.port.protocol; n->u.port.low_port = c->u.port.low_port; n->u.port.high_port = c->u.port.high_port; break; case OCON_NODE: n->u.node.addr = c->u.node.addr; n->u.node.mask = c->u.node.mask; break; case OCON_FSUSE: n->v.behavior = c->v.behavior; n->u.name = strdup(c->u.name); if (!n->u.name) { ERR(state->handle, "Out of memory!"); return -1; } break; case OCON_NODE6: for (j = 0; j < 4; j++) n->u.node6.addr[j] = c->u.node6.addr[j]; for (j = 0; j < 4; j++) n->u.node6.mask[j] = c->u.node6.mask[j]; break; default: /* shouldn't get here */ ERR(state->handle, "Unknown ocontext"); return -1; } if (context_copy(&n->context[0], &c->context[0], state)) { ERR(state->handle, "Out of memory!"); return -1; } } } return 0; } static int ocontext_copy(expand_state_t *state, uint32_t target) { int rc = -1; switch (target) { case SEPOL_TARGET_SELINUX: rc = ocontext_copy_selinux(state); break; case SEPOL_TARGET_XEN: rc = ocontext_copy_xen(state); break; default: ERR(state->handle, "Unknown target"); return -1; } return rc; } static int genfs_copy(expand_state_t * state) { ocontext_t *c, *newc, *l; genfs_t *genfs, *newgenfs, *end; end = NULL; for (genfs = state->base->genfs; genfs; genfs = genfs->next) { newgenfs = malloc(sizeof(genfs_t)); if (!newgenfs) { ERR(state->handle, "Out of memory!"); return -1; } memset(newgenfs, 0, sizeof(genfs_t)); newgenfs->fstype = strdup(genfs->fstype); if (!newgenfs->fstype) { free(newgenfs); ERR(state->handle, "Out of memory!"); return -1; } if (!end) state->out->genfs = newgenfs; else end->next = newgenfs; end = newgenfs; l = NULL; for (c = genfs->head; c; c = c->next) { newc = malloc(sizeof(ocontext_t)); if (!newc) { ERR(state->handle, "Out of memory!"); return -1; } memset(newc, 0, sizeof(ocontext_t)); newc->u.name = strdup(c->u.name); if (!newc->u.name) { ERR(state->handle, "Out of memory!"); free(newc); return -1; } newc->v.sclass = c->v.sclass; context_copy(&newc->context[0], &c->context[0], state); if (l) l->next = newc; else newgenfs->head = newc; l = newc; } } return 0; } static int type_attr_map(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *ptr) { type_datum_t *type; expand_state_t *state = ptr; policydb_t *p = state->out; unsigned int i; ebitmap_node_t *tnode; type = (type_datum_t *) datum; if (type->flavor == TYPE_ATTRIB) { if (ebitmap_cpy(&p->attr_type_map[type->s.value - 1], &type->types)) { ERR(state->handle, "Out of memory!"); return -1; } ebitmap_for_each_bit(&type->types, tnode, i) { if (!ebitmap_node_get_bit(tnode, i)) continue; if (ebitmap_set_bit(&p->type_attr_map[i], type->s.value - 1, 1)) { ERR(state->handle, "Out of memory!"); return -1; } } } return 0; } /* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy. * this should not be called until after all the blocks have been processed and the attributes in target policy * are complete. */ int expand_convert_type_set(policydb_t * p, uint32_t * typemap, type_set_t * set, ebitmap_t * types, unsigned char alwaysexpand) { type_set_t tmpset; type_set_init(&tmpset); if (map_ebitmap(&set->types, &tmpset.types, typemap)) return -1; if (map_ebitmap(&set->negset, &tmpset.negset, typemap)) return -1; tmpset.flags = set->flags; if (type_set_expand(&tmpset, types, p, alwaysexpand)) return -1; type_set_destroy(&tmpset); return 0; } /* Expand a rule into a given avtab - checking for conflicting type * rules. Return 1 on success, 0 if the rule conflicts with something * (and hence was not added), or -1 on error. */ int expand_rule(sepol_handle_t * handle, policydb_t * source_pol, avrule_t * source_rule, avtab_t * dest_avtab, cond_av_list_t ** cond, cond_av_list_t ** other, int enabled) { int retval; ebitmap_t stypes, ttypes; if (source_rule->specified & AVRULE_NEVERALLOW) return 1; ebitmap_init(&stypes); ebitmap_init(&ttypes); if (type_set_expand(&source_rule->stypes, &stypes, source_pol, 1)) return -1; if (type_set_expand(&source_rule->ttypes, &ttypes, source_pol, 1)) return -1; retval = expand_rule_helper(handle, source_pol, NULL, source_rule, dest_avtab, cond, other, enabled, &stypes, &ttypes); ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); return retval; } /* Expand a role set into an ebitmap containing the roles. * This handles the attribute and flags. * Attribute expansion depends on if the rolemap is available. * During module compile the rolemap is not available, the * possible duplicates of a regular role and the role attribute * the regular role belongs to could be properly handled by * copy_role_trans and copy_role_allow. */ int role_set_expand(role_set_t * x, ebitmap_t * r, policydb_t * out, policydb_t * base, uint32_t * rolemap) { unsigned int i; ebitmap_node_t *rnode; ebitmap_t mapped_roles, roles; policydb_t *p = out; role_datum_t *role; ebitmap_init(r); if (x->flags & ROLE_STAR) { for (i = 0; i < p->p_roles.nprim++; i++) if (ebitmap_set_bit(r, i, 1)) return -1; return 0; } ebitmap_init(&mapped_roles); ebitmap_init(&roles); if (rolemap) { assert(base != NULL); ebitmap_for_each_bit(&x->roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { /* take advantage of p_role_val_to_struct[] * of the base module */ role = base->role_val_to_struct[i]; assert(role != NULL); if (role->flavor == ROLE_ATTRIB) { if (ebitmap_union(&roles, &role->roles)) goto bad; } else { if (ebitmap_set_bit(&roles, i, 1)) goto bad; } } } if (map_ebitmap(&roles, &mapped_roles, rolemap)) goto bad; } else { if (ebitmap_cpy(&mapped_roles, &x->roles)) goto bad; } ebitmap_for_each_bit(&mapped_roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { if (ebitmap_set_bit(r, i, 1)) goto bad; } } ebitmap_destroy(&mapped_roles); ebitmap_destroy(&roles); /* if role is to be complimented, invert the entire bitmap here */ if (x->flags & ROLE_COMP) { for (i = 0; i < ebitmap_length(r); i++) { if (ebitmap_get_bit(r, i)) { if (ebitmap_set_bit(r, i, 0)) return -1; } else { if (ebitmap_set_bit(r, i, 1)) return -1; } } } return 0; bad: ebitmap_destroy(&mapped_roles); ebitmap_destroy(&roles); return -1; } /* Expand a type set into an ebitmap containing the types. This * handles the negset, attributes, and flags. * Attribute expansion depends on several factors: * - if alwaysexpand is 1, then they will be expanded, * - if the type set has a negset or flags, then they will be expanded, * - otherwise, they will not be expanded. */ int type_set_expand(type_set_t * set, ebitmap_t * t, policydb_t * p, unsigned char alwaysexpand) { unsigned int i; ebitmap_t types, neg_types; ebitmap_node_t *tnode; ebitmap_init(&types); ebitmap_init(t); if (alwaysexpand || ebitmap_length(&set->negset) || set->flags) { /* First go through the types and OR all the attributes to types */ ebitmap_for_each_bit(&set->types, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { if (p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) { if (ebitmap_union (&types, &p->type_val_to_struct[i]-> types)) { return -1; } } else { if (ebitmap_set_bit(&types, i, 1)) { return -1; } } } } } else { /* No expansion of attributes, just copy the set as is. */ if (ebitmap_cpy(&types, &set->types)) return -1; } /* Now do the same thing for negset */ ebitmap_init(&neg_types); ebitmap_for_each_bit(&set->negset, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) { if (ebitmap_union (&neg_types, &p->type_val_to_struct[i]->types)) { return -1; } } else { if (ebitmap_set_bit(&neg_types, i, 1)) { return -1; } } } } if (set->flags & TYPE_STAR) { /* set all types not in neg_types */ for (i = 0; i < p->p_types.nprim; i++) { if (ebitmap_get_bit(&neg_types, i)) continue; if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) continue; if (ebitmap_set_bit(t, i, 1)) return -1; } goto out; } ebitmap_for_each_bit(&types, tnode, i) { if (ebitmap_node_get_bit(tnode, i) && (!ebitmap_get_bit(&neg_types, i))) if (ebitmap_set_bit(t, i, 1)) return -1; } if (set->flags & TYPE_COMP) { for (i = 0; i < p->p_types.nprim; i++) { if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor == TYPE_ATTRIB) { assert(!ebitmap_get_bit(t, i)); continue; } if (ebitmap_get_bit(t, i)) { if (ebitmap_set_bit(t, i, 0)) return -1; } else { if (ebitmap_set_bit(t, i, 1)) return -1; } } } out: ebitmap_destroy(&types); ebitmap_destroy(&neg_types); return 0; } static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap, avrule_t * source_rule) { ebitmap_t stypes, ttypes; avrule_t *avrule; class_perm_node_t *cur_perm, *new_perm, *tail_perm; ebitmap_init(&stypes); ebitmap_init(&ttypes); if (expand_convert_type_set (dest_pol, typemap, &source_rule->stypes, &stypes, 1)) return -1; if (expand_convert_type_set (dest_pol, typemap, &source_rule->ttypes, &ttypes, 1)) return -1; avrule = (avrule_t *) malloc(sizeof(avrule_t)); if (!avrule) return -1; avrule_init(avrule); avrule->specified = AVRULE_NEVERALLOW; avrule->line = source_rule->line; avrule->flags = source_rule->flags; if (ebitmap_cpy(&avrule->stypes.types, &stypes)) goto err; if (ebitmap_cpy(&avrule->ttypes.types, &ttypes)) goto err; cur_perm = source_rule->perms; tail_perm = NULL; while (cur_perm) { new_perm = (class_perm_node_t *) malloc(sizeof(class_perm_node_t)); if (!new_perm) goto err; class_perm_node_init(new_perm); new_perm->class = cur_perm->class; assert(new_perm->class); /* once we have modules with permissions we'll need to map the permissions (and classes) */ new_perm->data = cur_perm->data; if (!avrule->perms) avrule->perms = new_perm; if (tail_perm) tail_perm->next = new_perm; tail_perm = new_perm; cur_perm = cur_perm->next; } /* just prepend the avrule to the first branch; it'll never be written to disk */ if (!dest_pol->global->branch_list->avrules) dest_pol->global->branch_list->avrules = avrule; else { avrule->next = dest_pol->global->branch_list->avrules; dest_pol->global->branch_list->avrules = avrule; } ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); return 0; err: ebitmap_destroy(&stypes); ebitmap_destroy(&ttypes); ebitmap_destroy(&avrule->stypes.types); ebitmap_destroy(&avrule->ttypes.types); cur_perm = avrule->perms; while (cur_perm) { tail_perm = cur_perm->next; free(cur_perm); cur_perm = tail_perm; } free(avrule); return -1; } /* * Expands the avrule blocks for a policy. RBAC rules are copied. Neverallow * rules are copied or expanded as per the settings in the state object; all * other AV rules are expanded. If neverallow rules are expanded, they are not * copied, otherwise they are copied for later use by the assertion checker. */ static int copy_and_expand_avrule_block(expand_state_t * state) { avrule_block_t *curblock = state->base->global; avrule_block_t *prevblock; int retval = -1; if (avtab_alloc(&state->out->te_avtab, MAX_AVTAB_SIZE)) { ERR(state->handle, "Out of Memory!"); return -1; } if (avtab_alloc(&state->out->te_cond_avtab, MAX_AVTAB_SIZE)) { ERR(state->handle, "Out of Memory!"); return -1; } while (curblock) { avrule_decl_t *decl = curblock->enabled; avrule_t *cur_avrule; if (decl == NULL) { /* nothing was enabled within this block */ goto cont; } /* copy role allows and role trans */ if (copy_role_allows(state, decl->role_allow_rules) != 0 || copy_role_trans(state, decl->role_tr_rules) != 0) { goto cleanup; } if (expand_filename_trans(state, decl->filename_trans_rules)) goto cleanup; /* expand the range transition rules */ if (expand_range_trans(state, decl->range_tr_rules)) goto cleanup; /* copy rules */ cur_avrule = decl->avrules; while (cur_avrule != NULL) { if (!(state->expand_neverallow) && cur_avrule->specified & AVRULE_NEVERALLOW) { /* copy this over directly so that assertions are checked later */ if (copy_neverallow (state->out, state->typemap, cur_avrule)) ERR(state->handle, "Error while copying neverallow."); } else { if (cur_avrule->specified & AVRULE_NEVERALLOW) { state->out->unsupported_format = 1; } if (convert_and_expand_rule (state->handle, state->out, state->typemap, cur_avrule, &state->out->te_avtab, NULL, NULL, 0, state->expand_neverallow) != EXPAND_RULE_SUCCESS) { goto cleanup; } } cur_avrule = cur_avrule->next; } /* copy conditional rules */ if (cond_node_copy(state, decl->cond_list)) goto cleanup; cont: prevblock = curblock; curblock = curblock->next; if (state->handle && state->handle->expand_consume_base) { /* set base top avrule block in case there * is an error condition and the policy needs * to be destroyed */ state->base->global = curblock; avrule_block_destroy(prevblock); } } retval = 0; cleanup: return retval; } /* * This function allows external users of the library (such as setools) to * expand only the avrules and optionally perform expansion of neverallow rules * or expand into the same policy for analysis purposes. */ int expand_module_avrules(sepol_handle_t * handle, policydb_t * base, policydb_t * out, uint32_t * typemap, uint32_t * boolmap, uint32_t * rolemap, uint32_t * usermap, int verbose, int expand_neverallow) { expand_state_t state; expand_state_init(&state); state.base = base; state.out = out; state.typemap = typemap; state.boolmap = boolmap; state.rolemap = rolemap; state.usermap = usermap; state.handle = handle; state.verbose = verbose; state.expand_neverallow = expand_neverallow; return copy_and_expand_avrule_block(&state); } static void discard_tunables(sepol_handle_t *sh, policydb_t *pol) { avrule_block_t *block; avrule_decl_t *decl; cond_node_t *cur_node; cond_expr_t *cur_expr; int cur_state, preserve_tunables = 0; avrule_t *tail, *to_be_appended; if (sh && sh->preserve_tunables) preserve_tunables = 1; /* Iterate through all cond_node of all enabled decls, if a cond_node * is about tunable, calculate its state value and concatenate one of * its avrule list to the current decl->avrules list. On the other * hand, the disabled unused branch of a tunable would be discarded. * * Note, such tunable cond_node would be skipped over in expansion, * so we won't have to worry about removing it from decl->cond_list * here :-) * * If tunables are requested to be preserved then they would be * "transformed" as booleans by having their TUNABLE flag cleared. */ for (block = pol->global; block != NULL; block = block->next) { decl = block->enabled; if (decl == NULL || decl->enabled == 0) continue; tail = decl->avrules; while (tail && tail->next) tail = tail->next; for (cur_node = decl->cond_list; cur_node != NULL; cur_node = cur_node->next) { int booleans, tunables, i; cond_bool_datum_t *booldatum; cond_bool_datum_t *tmp[COND_EXPR_MAXDEPTH]; booleans = tunables = 0; memset(tmp, 0, sizeof(cond_bool_datum_t *) * COND_EXPR_MAXDEPTH); for (cur_expr = cur_node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { if (cur_expr->expr_type != COND_BOOL) continue; booldatum = pol->bool_val_to_struct[cur_expr->bool - 1]; if (booldatum->flags & COND_BOOL_FLAGS_TUNABLE) tmp[tunables++] = booldatum; else booleans++; } /* bool_copy_callback() at link phase has ensured * that no mixture of tunables and booleans in one * expression. However, this would be broken by the * request to preserve tunables */ if (!preserve_tunables) assert(!(booleans && tunables)); if (booleans || preserve_tunables) { cur_node->flags &= ~COND_NODE_FLAGS_TUNABLE; if (tunables) { for (i = 0; i < tunables; i++) tmp[i]->flags &= ~COND_BOOL_FLAGS_TUNABLE; } } else { cur_node->flags |= COND_NODE_FLAGS_TUNABLE; cur_state = cond_evaluate_expr(pol, cur_node->expr); if (cur_state == -1) { printf("Expression result was " "undefined, skipping all" "rules\n"); continue; } to_be_appended = (cur_state == 1) ? cur_node->avtrue_list : cur_node->avfalse_list; if (tail) tail->next = to_be_appended; else tail = decl->avrules = to_be_appended; /* Now that the effective branch has been * appended, neutralize its original pointer */ if (cur_state == 1) cur_node->avtrue_list = NULL; else cur_node->avfalse_list = NULL; /* Update the tail of decl->avrules for * further concatenation */ while (tail && tail->next) tail = tail->next; } } } } /* Linking should always be done before calling expand, even if * there is only a base since all optionals are dealt with at link time * the base passed in should be indexed and avrule blocks should be * enabled. */ int expand_module(sepol_handle_t * handle, policydb_t * base, policydb_t * out, int verbose, int check) { int retval = -1; unsigned int i; expand_state_t state; avrule_block_t *curblock; /* Append tunable's avtrue_list or avfalse_list to the avrules list * of its home decl depending on its state value, so that the effect * rules of a tunable would be added to te_avtab permanently. Whereas * the disabled unused branch would be discarded. * * Originally this function is called at the very end of link phase, * however, we need to keep the linked policy intact for analysis * purpose. */ discard_tunables(handle, base); expand_state_init(&state); state.verbose = verbose; state.typemap = NULL; state.base = base; state.out = out; state.handle = handle; if (base->policy_type != POLICY_BASE) { ERR(handle, "Target of expand was not a base policy."); return -1; } state.out->policy_type = POLICY_KERN; state.out->policyvers = POLICYDB_VERSION_MAX; /* Copy mls state from base to out */ out->mls = base->mls; out->handle_unknown = base->handle_unknown; /* Copy target from base to out */ out->target_platform = base->target_platform; /* Copy policy capabilities */ if (ebitmap_cpy(&out->policycaps, &base->policycaps)) { ERR(handle, "Out of memory!"); goto cleanup; } if ((state.typemap = (uint32_t *) calloc(state.base->p_types.nprim, sizeof(uint32_t))) == NULL) { ERR(handle, "Out of memory!"); goto cleanup; } state.boolmap = (uint32_t *)calloc(state.base->p_bools.nprim, sizeof(uint32_t)); if (!state.boolmap) { ERR(handle, "Out of memory!"); goto cleanup; } state.rolemap = (uint32_t *)calloc(state.base->p_roles.nprim, sizeof(uint32_t)); if (!state.rolemap) { ERR(handle, "Out of memory!"); goto cleanup; } state.usermap = (uint32_t *)calloc(state.base->p_users.nprim, sizeof(uint32_t)); if (!state.usermap) { ERR(handle, "Out of memory!"); goto cleanup; } /* order is important - types must be first */ /* copy types */ if (hashtab_map(state.base->p_types.table, type_copy_callback, &state)) { goto cleanup; } /* convert attribute type sets */ if (hashtab_map (state.base->p_types.table, attr_convert_callback, &state)) { goto cleanup; } /* copy commons */ if (hashtab_map (state.base->p_commons.table, common_copy_callback, &state)) { goto cleanup; } /* copy classes, note, this does not copy constraints, constraints can't be * copied until after all the blocks have been processed and attributes are complete */ if (hashtab_map (state.base->p_classes.table, class_copy_callback, &state)) { goto cleanup; } /* copy type bounds */ if (hashtab_map(state.base->p_types.table, type_bounds_copy_callback, &state)) goto cleanup; /* copy aliases */ if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state)) goto cleanup; /* index here so that type indexes are available for role_copy_callback */ if (policydb_index_others(handle, out, verbose)) { ERR(handle, "Error while indexing out symbols"); goto cleanup; } /* copy roles */ if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state)) goto cleanup; if (hashtab_map(state.base->p_roles.table, role_bounds_copy_callback, &state)) goto cleanup; /* escalate the type_set_t in a role attribute to all regular roles * that belongs to it. */ if (hashtab_map(state.base->p_roles.table, role_fix_callback, &state)) goto cleanup; /* copy MLS's sensitivity level and categories - this needs to be done * before expanding users (they need to be indexed too) */ if (hashtab_map(state.base->p_levels.table, sens_copy_callback, &state)) goto cleanup; if (hashtab_map(state.base->p_cats.table, cats_copy_callback, &state)) goto cleanup; if (policydb_index_others(handle, out, verbose)) { ERR(handle, "Error while indexing out symbols"); goto cleanup; } /* copy users */ if (hashtab_map(state.base->p_users.table, user_copy_callback, &state)) goto cleanup; if (hashtab_map(state.base->p_users.table, user_bounds_copy_callback, &state)) goto cleanup; /* copy bools */ if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state)) goto cleanup; if (policydb_index_classes(out)) { ERR(handle, "Error while indexing out classes"); goto cleanup; } if (policydb_index_others(handle, out, verbose)) { ERR(handle, "Error while indexing out symbols"); goto cleanup; } /* loop through all decls and union attributes, roles, users */ for (curblock = state.base->global; curblock != NULL; curblock = curblock->next) { avrule_decl_t *decl = curblock->enabled; if (decl == NULL) { /* nothing was enabled within this block */ continue; } /* convert attribute type sets */ if (hashtab_map (decl->p_types.table, attr_convert_callback, &state)) { goto cleanup; } /* copy roles */ if (hashtab_map (decl->p_roles.table, role_copy_callback, &state)) goto cleanup; /* copy users */ if (hashtab_map (decl->p_users.table, user_copy_callback, &state)) goto cleanup; } /* remap role dominates bitmaps */ if (hashtab_map(state.out->p_roles.table, role_remap_dominates, &state)) { goto cleanup; } if (copy_and_expand_avrule_block(&state) < 0) { ERR(handle, "Error during expand"); goto cleanup; } /* copy constraints */ if (hashtab_map (state.base->p_classes.table, constraint_copy_callback, &state)) { goto cleanup; } cond_optimize_lists(state.out->cond_list); if (evaluate_conds(state.out)) goto cleanup; /* copy ocontexts */ if (ocontext_copy(&state, out->target_platform)) goto cleanup; /* copy genfs */ if (genfs_copy(&state)) goto cleanup; /* Build the type<->attribute maps and remove attributes. */ state.out->attr_type_map = malloc(state.out->p_types.nprim * sizeof(ebitmap_t)); state.out->type_attr_map = malloc(state.out->p_types.nprim * sizeof(ebitmap_t)); if (!state.out->attr_type_map || !state.out->type_attr_map) { ERR(handle, "Out of memory!"); goto cleanup; } for (i = 0; i < state.out->p_types.nprim; i++) { ebitmap_init(&state.out->type_attr_map[i]); ebitmap_init(&state.out->attr_type_map[i]); /* add the type itself as the degenerate case */ if (ebitmap_set_bit(&state.out->type_attr_map[i], i, 1)) { ERR(handle, "Out of memory!"); goto cleanup; } } if (hashtab_map(state.out->p_types.table, type_attr_map, &state)) goto cleanup; if (check) { if (hierarchy_check_constraints(handle, state.out)) goto cleanup; if (check_assertions (handle, state.out, state.out->global->branch_list->avrules)) goto cleanup; } retval = 0; cleanup: free(state.typemap); free(state.boolmap); free(state.rolemap); free(state.usermap); return retval; } static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d) { avtab_ptr_t node; avtab_datum_t *avd; int rc; node = avtab_search_node(a, k); if (!node) { rc = avtab_insert(a, k, d); if (rc) ERR(NULL, "Out of memory!"); return rc; } if ((k->specified & AVTAB_ENABLED) != (node->key.specified & AVTAB_ENABLED)) { node = avtab_insert_nonunique(a, k, d); if (!node) { ERR(NULL, "Out of memory!"); return -1; } return 0; } avd = &node->datum; switch (k->specified & ~AVTAB_ENABLED) { case AVTAB_ALLOWED: case AVTAB_AUDITALLOW: avd->data |= d->data; break; case AVTAB_AUDITDENY: avd->data &= d->data; break; default: ERR(NULL, "Type conflict!"); return -1; } return 0; } struct expand_avtab_data { avtab_t *expa; policydb_t *p; }; static int expand_avtab_node(avtab_key_t * k, avtab_datum_t * d, void *args) { struct expand_avtab_data *ptr = args; avtab_t *expa = ptr->expa; policydb_t *p = ptr->p; type_datum_t *stype = p->type_val_to_struct[k->source_type - 1]; type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1]; ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1]; ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1]; ebitmap_node_t *snode, *tnode; unsigned int i, j; avtab_key_t newkey; int rc; newkey.target_class = k->target_class; newkey.specified = k->specified; if (stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) { /* Both are individual types, no expansion required. */ return expand_avtab_insert(expa, k, d); } if (stype->flavor != TYPE_ATTRIB) { /* Source is an individual type, target is an attribute. */ newkey.source_type = k->source_type; ebitmap_for_each_bit(tattr, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; newkey.target_type = j + 1; rc = expand_avtab_insert(expa, &newkey, d); if (rc) return -1; } return 0; } if (ttype->flavor != TYPE_ATTRIB) { /* Target is an individual type, source is an attribute. */ newkey.target_type = k->target_type; ebitmap_for_each_bit(sattr, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; newkey.source_type = i + 1; rc = expand_avtab_insert(expa, &newkey, d); if (rc) return -1; } return 0; } /* Both source and target type are attributes. */ ebitmap_for_each_bit(sattr, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; ebitmap_for_each_bit(tattr, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; newkey.source_type = i + 1; newkey.target_type = j + 1; rc = expand_avtab_insert(expa, &newkey, d); if (rc) return -1; } } return 0; } int expand_avtab(policydb_t * p, avtab_t * a, avtab_t * expa) { struct expand_avtab_data data; if (avtab_alloc(expa, MAX_AVTAB_SIZE)) { ERR(NULL, "Out of memory!"); return -1; } data.expa = expa; data.p = p; return avtab_map(a, expand_avtab_node, &data); } static int expand_cond_insert(cond_av_list_t ** l, avtab_t * expa, avtab_key_t * k, avtab_datum_t * d) { avtab_ptr_t node; avtab_datum_t *avd; cond_av_list_t *nl; node = avtab_search_node(expa, k); if (!node || (k->specified & AVTAB_ENABLED) != (node->key.specified & AVTAB_ENABLED)) { node = avtab_insert_nonunique(expa, k, d); if (!node) { ERR(NULL, "Out of memory!"); return -1; } node->parse_context = (void *)1; nl = (cond_av_list_t *) malloc(sizeof(*nl)); if (!nl) { ERR(NULL, "Out of memory!"); return -1; } memset(nl, 0, sizeof(*nl)); nl->node = node; nl->next = *l; *l = nl; return 0; } avd = &node->datum; switch (k->specified & ~AVTAB_ENABLED) { case AVTAB_ALLOWED: case AVTAB_AUDITALLOW: avd->data |= d->data; break; case AVTAB_AUDITDENY: avd->data &= d->data; break; default: ERR(NULL, "Type conflict!"); return -1; } return 0; } int expand_cond_av_node(policydb_t * p, avtab_ptr_t node, cond_av_list_t ** newl, avtab_t * expa) { avtab_key_t *k = &node->key; avtab_datum_t *d = &node->datum; type_datum_t *stype = p->type_val_to_struct[k->source_type - 1]; type_datum_t *ttype = p->type_val_to_struct[k->target_type - 1]; ebitmap_t *sattr = &p->attr_type_map[k->source_type - 1]; ebitmap_t *tattr = &p->attr_type_map[k->target_type - 1]; ebitmap_node_t *snode, *tnode; unsigned int i, j; avtab_key_t newkey; int rc; newkey.target_class = k->target_class; newkey.specified = k->specified; if (stype->flavor != TYPE_ATTRIB && ttype->flavor != TYPE_ATTRIB) { /* Both are individual types, no expansion required. */ return expand_cond_insert(newl, expa, k, d); } if (stype->flavor != TYPE_ATTRIB) { /* Source is an individual type, target is an attribute. */ newkey.source_type = k->source_type; ebitmap_for_each_bit(tattr, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; newkey.target_type = j + 1; rc = expand_cond_insert(newl, expa, &newkey, d); if (rc) return -1; } return 0; } if (ttype->flavor != TYPE_ATTRIB) { /* Target is an individual type, source is an attribute. */ newkey.target_type = k->target_type; ebitmap_for_each_bit(sattr, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; newkey.source_type = i + 1; rc = expand_cond_insert(newl, expa, &newkey, d); if (rc) return -1; } return 0; } /* Both source and target type are attributes. */ ebitmap_for_each_bit(sattr, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; ebitmap_for_each_bit(tattr, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; newkey.source_type = i + 1; newkey.target_type = j + 1; rc = expand_cond_insert(newl, expa, &newkey, d); if (rc) return -1; } } return 0; } int expand_cond_av_list(policydb_t * p, cond_av_list_t * l, cond_av_list_t ** newl, avtab_t * expa) { cond_av_list_t *cur; avtab_ptr_t node; int rc; if (avtab_alloc(expa, MAX_AVTAB_SIZE)) { ERR(NULL, "Out of memory!"); return -1; } *newl = NULL; for (cur = l; cur; cur = cur->next) { node = cur->node; rc = expand_cond_av_node(p, node, newl, expa); if (rc) return rc; } return 0; } libsepol-2.2/src/genbools.c000066400000000000000000000124021223423440700157310ustar00rootroot00000000000000#include #include #include #include #include #include #include "debug.h" #include "private.h" #include "dso.h" /* -- Deprecated -- */ static char *strtrim(char *dest, char *source, int size) { int i = 0; char *ptr = source; i = 0; while (isspace(*ptr) && i < size) { ptr++; i++; } strncpy(dest, ptr, size); for (i = strlen(dest) - 1; i > 0; i--) { if (!isspace(dest[i])) break; } dest[i + 1] = '\0'; return dest; } static int process_boolean(char *buffer, char *name, int namesize, int *val) { char name1[BUFSIZ]; char *ptr = NULL; char *tok = strtok_r(buffer, "=", &ptr); if (tok) { strncpy(name1, tok, BUFSIZ - 1); strtrim(name, name1, namesize - 1); if (name[0] == '#') return 0; tok = strtok_r(NULL, "\0", &ptr); if (tok) { while (isspace(*tok)) tok++; *val = -1; if (isdigit(tok[0])) *val = atoi(tok); else if (!strncasecmp(tok, "true", sizeof("true") - 1)) *val = 1; else if (!strncasecmp (tok, "false", sizeof("false") - 1)) *val = 0; if (*val != 0 && *val != 1) { ERR(NULL, "illegal value for boolean " "%s=%s", name, tok); return -1; } } } return 1; } static int load_booleans(struct policydb *policydb, const char *path, int *changesp) { FILE *boolf; char *buffer = NULL; size_t size = 0; char localbools[BUFSIZ]; char name[BUFSIZ]; int val; int errors = 0, changes = 0; struct cond_bool_datum *datum; boolf = fopen(path, "r"); if (boolf == NULL) goto localbool; #ifdef DARWIN if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) { ERR(NULL, "out of memory"); return -1; } while(fgets(buffer, 255, boolf) != NULL) { #else while (getline(&buffer, &size, boolf) > 0) { #endif int ret = process_boolean(buffer, name, sizeof(name), &val); if (ret == -1) errors++; if (ret == 1) { datum = hashtab_search(policydb->p_bools.table, name); if (!datum) { ERR(NULL, "unknown boolean %s", name); errors++; continue; } if (datum->state != val) { datum->state = val; changes++; } } } fclose(boolf); localbool: snprintf(localbools, sizeof(localbools), "%s.local", path); boolf = fopen(localbools, "r"); if (boolf != NULL) { #ifdef DARWIN while(fgets(buffer, 255, boolf) != NULL) { #else while (getline(&buffer, &size, boolf) > 0) { #endif int ret = process_boolean(buffer, name, sizeof(name), &val); if (ret == -1) errors++; if (ret == 1) { datum = hashtab_search(policydb->p_bools.table, name); if (!datum) { ERR(NULL, "unknown boolean %s", name); errors++; continue; } if (datum->state != val) { datum->state = val; changes++; } } } fclose(boolf); } free(buffer); if (errors) errno = EINVAL; *changesp = changes; return errors ? -1 : 0; } int sepol_genbools(void *data, size_t len, char *booleans) { struct policydb policydb; struct policy_file pf; int rc, changes = 0; if (policydb_init(&policydb)) goto err; if (policydb_from_image(NULL, data, len, &policydb) < 0) goto err; if (load_booleans(&policydb, booleans, &changes) < 0) { WARN(NULL, "error while reading %s", booleans); } if (!changes) goto out; if (evaluate_conds(&policydb) < 0) { ERR(NULL, "error while re-evaluating conditionals"); errno = EINVAL; goto err_destroy; } policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = data; pf.len = len; rc = policydb_write(&policydb, &pf); if (rc) { ERR(NULL, "unable to write new binary policy image"); errno = EINVAL; goto err_destroy; } out: policydb_destroy(&policydb); return 0; err_destroy: policydb_destroy(&policydb); err: return -1; } int hidden sepol_genbools_policydb(policydb_t * policydb, const char *booleans) { int rc, changes = 0; rc = load_booleans(policydb, booleans, &changes); if (!rc && changes) rc = evaluate_conds(policydb); if (rc) errno = EINVAL; return rc; } /* -- End Deprecated -- */ int sepol_genbools_array(void *data, size_t len, char **names, int *values, int nel) { struct policydb policydb; struct policy_file pf; int rc, i, errors = 0; struct cond_bool_datum *datum; /* Create policy database from image */ if (policydb_init(&policydb)) goto err; if (policydb_from_image(NULL, data, len, &policydb) < 0) goto err; for (i = 0; i < nel; i++) { datum = hashtab_search(policydb.p_bools.table, names[i]); if (!datum) { ERR(NULL, "boolean %s no longer in policy", names[i]); errors++; continue; } if (values[i] != 0 && values[i] != 1) { ERR(NULL, "illegal value %d for boolean %s", values[i], names[i]); errors++; continue; } datum->state = values[i]; } if (evaluate_conds(&policydb) < 0) { ERR(NULL, "error while re-evaluating conditionals"); errno = EINVAL; goto err_destroy; } policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = data; pf.len = len; rc = policydb_write(&policydb, &pf); if (rc) { ERR(NULL, "unable to write binary policy"); errno = EINVAL; goto err_destroy; } if (errors) { errno = EINVAL; goto err_destroy; } policydb_destroy(&policydb); return 0; err_destroy: policydb_destroy(&policydb); err: return -1; } libsepol-2.2/src/genusers.c000066400000000000000000000146141223423440700157630ustar00rootroot00000000000000#include #include #include #include #include #include #ifndef DARWIN #include #endif #include #include "debug.h" #include "private.h" #include "dso.h" #include "mls.h" /* -- Deprecated -- */ void sepol_set_delusers(int on __attribute((unused))) { WARN(NULL, "Deprecated interface"); } #undef BADLINE #define BADLINE() { \ ERR(NULL, "invalid entry %s (%s:%u)", \ buffer, path, lineno); \ continue; \ } static int load_users(struct policydb *policydb, const char *path) { FILE *fp; char *buffer = NULL, *p, *q, oldc; size_t len = 0; ssize_t nread; unsigned lineno = 0, islist = 0, bit; user_datum_t *usrdatum; role_datum_t *roldatum; ebitmap_node_t *rnode; fp = fopen(path, "r"); if (fp == NULL) return -1; #ifdef DARWIN if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) { ERR(NULL, "out of memory"); return -1; } while(fgets(buffer, 255, fp) != NULL) { #else __fsetlocking(fp, FSETLOCKING_BYCALLER); while ((nread = getline(&buffer, &len, fp)) > 0) { #endif lineno++; if (buffer[nread - 1] == '\n') buffer[nread - 1] = 0; p = buffer; while (*p && isspace(*p)) p++; if (!(*p) || *p == '#') continue; if (strncasecmp(p, "user", 4)) BADLINE(); p += 4; if (!isspace(*p)) BADLINE(); while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); q = p; while (*p && !isspace(*p)) p++; if (!(*p)) BADLINE(); *p++ = 0; usrdatum = hashtab_search(policydb->p_users.table, q); if (usrdatum) { /* Replacing an existing user definition. */ ebitmap_destroy(&usrdatum->roles.roles); ebitmap_init(&usrdatum->roles.roles); } else { char *id = strdup(q); if (!id) { ERR(NULL, "out of memory"); free(buffer); fclose(fp); return -1; } /* Adding a new user definition. */ usrdatum = malloc(sizeof(user_datum_t)); if (!usrdatum) { ERR(NULL, "out of memory"); free(buffer); free(id); fclose(fp); return -1; } user_datum_init(usrdatum); usrdatum->s.value = ++policydb->p_users.nprim; if (hashtab_insert(policydb->p_users.table, id, (hashtab_datum_t) usrdatum)) { ERR(NULL, "out of memory"); free(buffer); free(id); user_datum_destroy(usrdatum); free(usrdatum); fclose(fp); return -1; } } while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); if (strncasecmp(p, "roles", 5)) BADLINE(); p += 5; if (!isspace(*p)) BADLINE(); while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); if (*p == '{') { islist = 1; p++; } else islist = 0; oldc = 0; do { while (*p && isspace(*p)) p++; if (!(*p)) break; q = p; while (*p && *p != ';' && *p != '}' && !isspace(*p)) p++; if (!(*p)) break; if (*p == '}') islist = 0; oldc = *p; *p++ = 0; if (!q[0]) break; roldatum = hashtab_search(policydb->p_roles.table, q); if (!roldatum) { ERR(NULL, "undefined role %s (%s:%u)", q, path, lineno); continue; } /* Set the role and every role it dominates */ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) { if (ebitmap_node_get_bit(rnode, bit)) if (ebitmap_set_bit (&usrdatum->roles.roles, bit, 1)) { ERR(NULL, "out of memory"); free(buffer); fclose(fp); return -1; } } } while (islist); if (oldc == 0) BADLINE(); if (policydb->mls) { context_struct_t context; char *scontext, *r, *s; while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); if (strncasecmp(p, "level", 5)) BADLINE(); p += 5; if (!isspace(*p)) BADLINE(); while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); q = p; while (*p && strncasecmp(p, "range", 5)) p++; if (!(*p)) BADLINE(); *--p = 0; p++; scontext = malloc(p - q); if (!scontext) { ERR(NULL, "out of memory"); free(buffer); fclose(fp); return -1; } r = scontext; s = q; while (*s) { if (!isspace(*s)) *r++ = *s; s++; } *r = 0; r = scontext; context_init(&context); if (mls_context_to_sid(policydb, oldc, &r, &context) < 0) { ERR(NULL, "invalid level %s (%s:%u)", scontext, path, lineno); free(scontext); continue; } free(scontext); memcpy(&usrdatum->dfltlevel, &context.range.level[0], sizeof(usrdatum->dfltlevel)); if (strncasecmp(p, "range", 5)) BADLINE(); p += 5; if (!isspace(*p)) BADLINE(); while (*p && isspace(*p)) p++; if (!(*p)) BADLINE(); q = p; while (*p && *p != ';') p++; if (!(*p)) BADLINE(); *p++ = 0; scontext = malloc(p - q); if (!scontext) { ERR(NULL, "out of memory"); free(buffer); fclose(fp); return -1; } r = scontext; s = q; while (*s) { if (!isspace(*s)) *r++ = *s; s++; } *r = 0; r = scontext; context_init(&context); if (mls_context_to_sid(policydb, oldc, &r, &context) < 0) { ERR(NULL, "invalid range %s (%s:%u)", scontext, path, lineno); free(scontext); continue; } free(scontext); memcpy(&usrdatum->range, &context.range, sizeof(usrdatum->range)); } } free(buffer); fclose(fp); return 0; } int sepol_genusers(void *data, size_t len, const char *usersdir, void **newdata, size_t * newlen) { struct policydb policydb; char path[PATH_MAX]; /* Construct policy database */ if (policydb_init(&policydb)) goto err; if (policydb_from_image(NULL, data, len, &policydb) < 0) goto err; /* Load locally defined users. */ snprintf(path, sizeof path, "%s/local.users", usersdir); if (load_users(&policydb, path) < 0) goto err_destroy; /* Write policy database */ if (policydb_to_image(NULL, &policydb, newdata, newlen) < 0) goto err_destroy; policydb_destroy(&policydb); return 0; err_destroy: policydb_destroy(&policydb); err: return -1; } int hidden sepol_genusers_policydb(policydb_t * policydb, const char *usersdir) { char path[PATH_MAX]; /* Load locally defined users. */ snprintf(path, sizeof path, "%s/local.users", usersdir); if (load_users(policydb, path) < 0) { ERR(NULL, "unable to load local.users: %s", strerror(errno)); return -1; } if (policydb_reindex_users(policydb) < 0) { ERR(NULL, "unable to reindex users: %s", strerror(errno)); return -1; } return 0; } /* -- End Deprecated -- */ libsepol-2.2/src/handle.c000066400000000000000000000023311223423440700153540ustar00rootroot00000000000000#include #include #include "handle.h" #include "debug.h" sepol_handle_t *sepol_handle_create(void) { sepol_handle_t *sh = malloc(sizeof(sepol_handle_t)); if (sh == NULL) return NULL; /* Set callback */ sh->msg_callback = sepol_msg_default_handler; sh->msg_callback_arg = NULL; /* by default do not disable dontaudits */ sh->disable_dontaudit = 0; sh->expand_consume_base = 0; /* by default needless unused branch of tunables would be discarded */ sh->preserve_tunables = 0; return sh; } int sepol_get_preserve_tunables(sepol_handle_t *sh) { assert(sh != NULL); return sh->preserve_tunables; } void sepol_set_preserve_tunables(sepol_handle_t * sh, int preserve_tunables) { assert(sh !=NULL); sh->preserve_tunables = preserve_tunables; } int sepol_get_disable_dontaudit(sepol_handle_t *sh) { assert(sh !=NULL); return sh->disable_dontaudit; } void sepol_set_disable_dontaudit(sepol_handle_t * sh, int disable_dontaudit) { assert(sh !=NULL); sh->disable_dontaudit = disable_dontaudit; } void sepol_set_expand_consume_base(sepol_handle_t *sh, int consume_base) { assert(sh != NULL); sh->expand_consume_base = consume_base; } void sepol_handle_destroy(sepol_handle_t * sh) { free(sh); } libsepol-2.2/src/handle.h000066400000000000000000000007301223423440700153620ustar00rootroot00000000000000#ifndef _SEPOL_INTERNAL_HANDLE_H_ #define _SEPOL_INTERNAL_HANDLE_H_ #include struct sepol_handle { /* Error handling */ int msg_level; const char *msg_channel; const char *msg_fname; #ifdef __GNUC__ __attribute__ ((format(printf, 3, 4))) #endif void (*msg_callback) (void *varg, sepol_handle_t * handle, const char *fmt, ...); void *msg_callback_arg; int disable_dontaudit; int expand_consume_base; int preserve_tunables; }; #endif libsepol-2.2/src/hashtab.c000066400000000000000000000144641223423440700155450ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated : Karl MacMillan * * Copyright (C) 2007 Red Hat, Inc. * * 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 */ /* FLASK */ /* * Implementation of the hash table type. */ #include #include #include hashtab_t hashtab_create(unsigned int (*hash_value) (hashtab_t h, const hashtab_key_t key), int (*keycmp) (hashtab_t h, const hashtab_key_t key1, const hashtab_key_t key2), unsigned int size) { hashtab_t p; unsigned int i; p = (hashtab_t) malloc(sizeof(hashtab_val_t)); if (p == NULL) return p; memset(p, 0, sizeof(hashtab_val_t)); p->size = size; p->nel = 0; p->hash_value = hash_value; p->keycmp = keycmp; p->htable = (hashtab_ptr_t *) malloc(sizeof(hashtab_ptr_t) * size); if (p->htable == NULL) { free(p); return NULL; } for (i = 0; i < size; i++) p->htable[i] = (hashtab_ptr_t) NULL; return p; } int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum) { int hvalue; hashtab_ptr_t prev, cur, newnode; if (!h) return SEPOL_ENOMEM; hvalue = h->hash_value(h, key); prev = NULL; cur = h->htable[hvalue]; while (cur && h->keycmp(h, key, cur->key) > 0) { prev = cur; cur = cur->next; } if (cur && (h->keycmp(h, key, cur->key) == 0)) return SEPOL_EEXIST; newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t)); if (newnode == NULL) return SEPOL_ENOMEM; memset(newnode, 0, sizeof(struct hashtab_node)); newnode->key = key; newnode->datum = datum; if (prev) { newnode->next = prev->next; prev->next = newnode; } else { newnode->next = h->htable[hvalue]; h->htable[hvalue] = newnode; } h->nel++; return SEPOL_OK; } int hashtab_remove(hashtab_t h, hashtab_key_t key, void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args) { int hvalue; hashtab_ptr_t cur, last; if (!h) return SEPOL_ENOENT; hvalue = h->hash_value(h, key); last = NULL; cur = h->htable[hvalue]; while (cur != NULL && h->keycmp(h, key, cur->key) > 0) { last = cur; cur = cur->next; } if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) return SEPOL_ENOENT; if (last == NULL) h->htable[hvalue] = cur->next; else last->next = cur->next; if (destroy) destroy(cur->key, cur->datum, args); free(cur); h->nel--; return SEPOL_OK; } int hashtab_replace(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum, void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args) { int hvalue; hashtab_ptr_t prev, cur, newnode; if (!h) return SEPOL_ENOMEM; hvalue = h->hash_value(h, key); prev = NULL; cur = h->htable[hvalue]; while (cur != NULL && h->keycmp(h, key, cur->key) > 0) { prev = cur; cur = cur->next; } if (cur && (h->keycmp(h, key, cur->key) == 0)) { if (destroy) destroy(cur->key, cur->datum, args); cur->key = key; cur->datum = datum; } else { newnode = (hashtab_ptr_t) malloc(sizeof(hashtab_node_t)); if (newnode == NULL) return SEPOL_ENOMEM; memset(newnode, 0, sizeof(struct hashtab_node)); newnode->key = key; newnode->datum = datum; if (prev) { newnode->next = prev->next; prev->next = newnode; } else { newnode->next = h->htable[hvalue]; h->htable[hvalue] = newnode; } } return SEPOL_OK; } hashtab_datum_t hashtab_search(hashtab_t h, const hashtab_key_t key) { int hvalue; hashtab_ptr_t cur; if (!h) return NULL; hvalue = h->hash_value(h, key); cur = h->htable[hvalue]; while (cur != NULL && h->keycmp(h, key, cur->key) > 0) cur = cur->next; if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) return NULL; return cur->datum; } void hashtab_destroy(hashtab_t h) { unsigned int i; hashtab_ptr_t cur, temp; if (!h) return; for (i = 0; i < h->size; i++) { cur = h->htable[i]; while (cur != NULL) { temp = cur; cur = cur->next; free(temp); } h->htable[i] = NULL; } free(h->htable); h->htable = NULL; free(h); } int hashtab_map(hashtab_t h, int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args) { unsigned int i, ret; hashtab_ptr_t cur; if (!h) return SEPOL_OK; for (i = 0; i < h->size; i++) { cur = h->htable[i]; while (cur != NULL) { ret = apply(cur->key, cur->datum, args); if (ret) return ret; cur = cur->next; } } return SEPOL_OK; } void hashtab_map_remove_on_error(hashtab_t h, int (*apply) (hashtab_key_t k, hashtab_datum_t d, void *args), void (*destroy) (hashtab_key_t k, hashtab_datum_t d, void *args), void *args) { unsigned int i; int ret; hashtab_ptr_t last, cur, temp; if (!h) return; for (i = 0; i < h->size; i++) { last = NULL; cur = h->htable[i]; while (cur != NULL) { ret = apply(cur->key, cur->datum, args); if (ret) { if (last) { last->next = cur->next; } else { h->htable[i] = cur->next; } temp = cur; cur = cur->next; if (destroy) destroy(temp->key, temp->datum, args); free(temp); h->nel--; } else { last = cur; cur = cur->next; } } } return; } void hashtab_hash_eval(hashtab_t h, char *tag) { unsigned int i; int chain_len, slots_used, max_chain_len; hashtab_ptr_t cur; slots_used = 0; max_chain_len = 0; for (i = 0; i < h->size; i++) { cur = h->htable[i]; if (cur) { slots_used++; chain_len = 0; while (cur) { chain_len++; cur = cur->next; } if (chain_len > max_chain_len) max_chain_len = chain_len; } } printf ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", tag, h->nel, slots_used, h->size, max_chain_len); } libsepol-2.2/src/hierarchy.c000066400000000000000000000324361223423440700161100ustar00rootroot00000000000000/* Authors: Joshua Brindle * Jason Tang * * Updates: KaiGai Kohei * adds checks based on newer boundary facility. * * A set of utility functions that aid policy decision when dealing * with hierarchal namespaces. * * Copyright (C) 2005 Tresys Technology, LLC * * Copyright (c) 2008 NEC Corporation * * 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 #include #include #include #include #include #include #include #include "debug.h" typedef struct hierarchy_args { policydb_t *p; avtab_t *expa; /* expanded avtab */ /* This tells check_avtab_hierarchy to check this list in addition to the unconditional avtab */ cond_av_list_t *opt_cond_list; sepol_handle_t *handle; int numerr; } hierarchy_args_t; /* * find_parent_(type|role|user) * * This function returns the parent datum of given XXX_datum_t * object or NULL, if it doesn't exist. * * If the given datum has a valid bounds, this function merely * returns the indicated object. Otherwise, it looks up the * parent based on the based hierarchy. */ #define find_parent_template(prefix) \ int find_parent_##prefix(hierarchy_args_t *a, \ prefix##_datum_t *datum, \ prefix##_datum_t **parent) \ { \ char *parent_name, *datum_name, *tmp; \ \ if (datum->bounds) \ *parent = a->p->prefix##_val_to_struct[datum->bounds - 1]; \ else { \ datum_name = a->p->p_##prefix##_val_to_name[datum->s.value - 1]; \ \ tmp = strrchr(datum_name, '.'); \ /* no '.' means it has no parent */ \ if (!tmp) { \ *parent = NULL; \ return 0; \ } \ \ parent_name = strdup(datum_name); \ if (!parent_name) \ return -1; \ parent_name[tmp - datum_name] = '\0'; \ \ *parent = hashtab_search(a->p->p_##prefix##s.table, parent_name); \ if (!*parent) { \ /* Orphan type/role/user */ \ ERR(a->handle, \ "%s doesn't exist, %s is an orphan", \ parent_name, \ a->p->p_##prefix##_val_to_name[datum->s.value - 1]); \ free(parent_name); \ return -1; \ } \ free(parent_name); \ } \ \ return 0; \ } static find_parent_template(type) static find_parent_template(role) static find_parent_template(user) static void compute_avtab_datum(hierarchy_args_t *args, avtab_key_t *key, avtab_datum_t *result) { avtab_datum_t *avdatp; uint32_t av = 0; avdatp = avtab_search(args->expa, key); if (avdatp) av = avdatp->data; if (args->opt_cond_list) { avdatp = cond_av_list_search(key, args->opt_cond_list); if (avdatp) av |= avdatp->data; } result->data = av; } /* This function verifies that the type passed in either has a parent or is in the * root of the namespace, 0 on success, 1 on orphan and -1 on error */ static int check_type_hierarchy_callback(hashtab_key_t k, hashtab_datum_t d, void *args) { hierarchy_args_t *a; type_datum_t *t, *tp; a = (hierarchy_args_t *) args; t = (type_datum_t *) d; if (t->flavor == TYPE_ATTRIB) { /* It's an attribute, we don't care */ return 0; } if (find_parent_type(a, t, &tp) < 0) return -1; if (tp && tp->flavor == TYPE_ATTRIB) { /* The parent is an attribute but the child isn't, not legal */ ERR(a->handle, "type %s is a child of an attribute %s", (char *) k, a->p->p_type_val_to_name[tp->s.value - 1]); a->numerr++; return -1; } return 0; } /* This function only verifies that the avtab node passed in does not violate any * hiearchy constraint via any relationship with other types in the avtab. * it should be called using avtab_map, returns 0 on success, 1 on violation and * -1 on error. opt_cond_list is an optional argument that tells this to check * a conditional list for the relationship as well as the unconditional avtab */ static int check_avtab_hierarchy_callback(avtab_key_t * k, avtab_datum_t * d, void *args) { avtab_key_t key; hierarchy_args_t *a = (hierarchy_args_t *) args; type_datum_t *s, *t1 = NULL, *t2 = NULL; avtab_datum_t av; if (!(k->specified & AVTAB_ALLOWED)) { /* This is not an allow rule, no checking done */ return 0; } /* search for parent first */ s = a->p->type_val_to_struct[k->source_type - 1]; if (find_parent_type(a, s, &t1) < 0) return -1; if (t1) { /* * search for access allowed between type 1's * parent and type 2. */ key.source_type = t1->s.value; key.target_type = k->target_type; key.target_class = k->target_class; key.specified = AVTAB_ALLOWED; compute_avtab_datum(a, &key, &av); if ((av.data & d->data) == d->data) return 0; } /* next we try type 1 and type 2's parent */ s = a->p->type_val_to_struct[k->target_type - 1]; if (find_parent_type(a, s, &t2) < 0) return -1; if (t2) { /* * search for access allowed between type 1 and * type 2's parent. */ key.source_type = k->source_type; key.target_type = t2->s.value; key.target_class = k->target_class; key.specified = AVTAB_ALLOWED; compute_avtab_datum(a, &key, &av); if ((av.data & d->data) == d->data) return 0; } if (t1 && t2) { /* * search for access allowed between type 1's parent * and type 2's parent. */ key.source_type = t1->s.value; key.target_type = t2->s.value; key.target_class = k->target_class; key.specified = AVTAB_ALLOWED; compute_avtab_datum(a, &key, &av); if ((av.data & d->data) == d->data) return 0; } /* * Neither one of these types have parents and * therefore the hierarchical constraint does not apply */ if (!t1 && !t2) return 0; /* * At this point there is a violation of the hierarchal * constraint, send error condition back */ ERR(a->handle, "hierarchy violation between types %s and %s : %s { %s }", a->p->p_type_val_to_name[k->source_type - 1], a->p->p_type_val_to_name[k->target_type - 1], a->p->p_class_val_to_name[k->target_class - 1], sepol_av_to_string(a->p, k->target_class, d->data & ~av.data)); a->numerr++; return 0; } /* * If same permissions are allowed for same combination of * source and target, we can evaluate them as unconditional * one. * See the following example. A_t type is bounds of B_t type, * so B_t can never have wider permissions then A_t. * A_t has conditional permission on X_t, however, a part of * them (getattr and read) are unconditionaly allowed to A_t. * * Example) * typebounds A_t B_t; * * allow B_t X_t : file { getattr }; * if (foo_bool) { * allow A_t X_t : file { getattr read }; * } else { * allow A_t X_t : file { getattr read write }; * } * * We have to pull up them as unconditional ones in this case, * because it seems to us B_t is violated to bounds constraints * during unconditional policy checking. */ static int pullup_unconditional_perms(cond_list_t * cond_list, hierarchy_args_t * args) { cond_list_t *cur_node; cond_av_list_t *cur_av, *expl_true = NULL, *expl_false = NULL; avtab_t expa_true, expa_false; avtab_datum_t *avdatp; avtab_datum_t avdat; avtab_ptr_t avnode; for (cur_node = cond_list; cur_node; cur_node = cur_node->next) { if (avtab_init(&expa_true)) goto oom0; if (avtab_init(&expa_false)) goto oom1; if (expand_cond_av_list(args->p, cur_node->true_list, &expl_true, &expa_true)) goto oom2; if (expand_cond_av_list(args->p, cur_node->false_list, &expl_false, &expa_false)) goto oom3; for (cur_av = expl_true; cur_av; cur_av = cur_av->next) { avdatp = avtab_search(&expa_false, &cur_av->node->key); if (!avdatp) continue; avdat.data = (cur_av->node->datum.data & avdatp->data); if (!avdat.data) continue; avnode = avtab_search_node(args->expa, &cur_av->node->key); if (avnode) { avnode->datum.data |= avdat.data; } else { if (avtab_insert(args->expa, &cur_av->node->key, &avdat)) goto oom4; } } cond_av_list_destroy(expl_false); cond_av_list_destroy(expl_true); avtab_destroy(&expa_false); avtab_destroy(&expa_true); } return 0; oom4: cond_av_list_destroy(expl_false); oom3: cond_av_list_destroy(expl_true); oom2: avtab_destroy(&expa_false); oom1: avtab_destroy(&expa_true); oom0: ERR(args->handle, "out of memory on conditional av list expansion"); return 1; } static int check_cond_avtab_hierarchy(cond_list_t * cond_list, hierarchy_args_t * args) { int rc; cond_list_t *cur_node; cond_av_list_t *cur_av, *expl = NULL; avtab_t expa; hierarchy_args_t *a = (hierarchy_args_t *) args; avtab_datum_t avdat, *uncond; for (cur_node = cond_list; cur_node; cur_node = cur_node->next) { /* * Check true condition */ if (avtab_init(&expa)) goto oom; if (expand_cond_av_list(args->p, cur_node->true_list, &expl, &expa)) { avtab_destroy(&expa); goto oom; } args->opt_cond_list = expl; for (cur_av = expl; cur_av; cur_av = cur_av->next) { avdat.data = cur_av->node->datum.data; uncond = avtab_search(a->expa, &cur_av->node->key); if (uncond) avdat.data |= uncond->data; rc = check_avtab_hierarchy_callback(&cur_av->node->key, &avdat, args); if (rc) args->numerr++; } cond_av_list_destroy(expl); avtab_destroy(&expa); /* * Check false condition */ if (avtab_init(&expa)) goto oom; if (expand_cond_av_list(args->p, cur_node->false_list, &expl, &expa)) { avtab_destroy(&expa); goto oom; } args->opt_cond_list = expl; for (cur_av = expl; cur_av; cur_av = cur_av->next) { avdat.data = cur_av->node->datum.data; uncond = avtab_search(a->expa, &cur_av->node->key); if (uncond) avdat.data |= uncond->data; rc = check_avtab_hierarchy_callback(&cur_av->node->key, &avdat, args); if (rc) a->numerr++; } cond_av_list_destroy(expl); avtab_destroy(&expa); } return 0; oom: ERR(args->handle, "out of memory on conditional av list expansion"); return 1; } /* The role hierarchy is defined as: a child role cannot have more types than it's parent. * This function should be called with hashtab_map, it will return 0 on success, 1 on * constraint violation and -1 on error */ static int check_role_hierarchy_callback(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args) { hierarchy_args_t *a; role_datum_t *r, *rp; a = (hierarchy_args_t *) args; r = (role_datum_t *) d; if (find_parent_role(a, r, &rp) < 0) return -1; if (rp && !ebitmap_contains(&rp->types.types, &r->types.types)) { /* hierarchical constraint violation, return error */ ERR(a->handle, "Role hierarchy violation, %s exceeds %s", (char *) k, a->p->p_role_val_to_name[rp->s.value - 1]); a->numerr++; } return 0; } /* The user hierarchy is defined as: a child user cannot have a role that * its parent doesn't have. This function should be called with hashtab_map, * it will return 0 on success, 1 on constraint violation and -1 on error. */ static int check_user_hierarchy_callback(hashtab_key_t k __attribute__ ((unused)), hashtab_datum_t d, void *args) { hierarchy_args_t *a; user_datum_t *u, *up; a = (hierarchy_args_t *) args; u = (user_datum_t *) d; if (find_parent_user(a, u, &up) < 0) return -1; if (up && !ebitmap_contains(&up->roles.roles, &u->roles.roles)) { /* hierarchical constraint violation, return error */ ERR(a->handle, "User hierarchy violation, %s exceeds %s", (char *) k, a->p->p_user_val_to_name[up->s.value - 1]); a->numerr++; } return 0; } int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p) { hierarchy_args_t args; avtab_t expa; if (avtab_init(&expa)) goto oom; if (expand_avtab(p, &p->te_avtab, &expa)) { avtab_destroy(&expa); goto oom; } args.p = p; args.expa = &expa; args.opt_cond_list = NULL; args.handle = handle; args.numerr = 0; if (hashtab_map(p->p_types.table, check_type_hierarchy_callback, &args)) goto bad; if (pullup_unconditional_perms(p->cond_list, &args)) return -1; if (avtab_map(&expa, check_avtab_hierarchy_callback, &args)) goto bad; if (check_cond_avtab_hierarchy(p->cond_list, &args)) goto bad; if (hashtab_map(p->p_roles.table, check_role_hierarchy_callback, &args)) goto bad; if (hashtab_map(p->p_users.table, check_user_hierarchy_callback, &args)) goto bad; if (args.numerr) { ERR(handle, "%d total errors found during hierarchy check", args.numerr); goto bad; } avtab_destroy(&expa); return 0; bad: avtab_destroy(&expa); return -1; oom: ERR(handle, "Out of memory"); return -1; } libsepol-2.2/src/iface_internal.h000066400000000000000000000010401223423440700170650ustar00rootroot00000000000000#ifndef _SEPOL_IFACE_INTERNAL_H_ #define _SEPOL_IFACE_INTERNAL_H_ #include #include #include "dso.h" hidden_proto(sepol_iface_create) hidden_proto(sepol_iface_free) hidden_proto(sepol_iface_get_ifcon) hidden_proto(sepol_iface_get_msgcon) hidden_proto(sepol_iface_get_name) hidden_proto(sepol_iface_key_create) hidden_proto(sepol_iface_key_unpack) hidden_proto(sepol_iface_set_ifcon) hidden_proto(sepol_iface_set_msgcon) hidden_proto(sepol_iface_set_name) #endif libsepol-2.2/src/iface_record.c000066400000000000000000000110071223423440700165260ustar00rootroot00000000000000#include #include #include "iface_internal.h" #include "context_internal.h" #include "debug.h" struct sepol_iface { /* Interface name */ char *name; /* Interface context */ sepol_context_t *netif_con; /* Message context */ sepol_context_t *netmsg_con; }; struct sepol_iface_key { /* Interface name */ const char *name; }; /* Key */ int sepol_iface_key_create(sepol_handle_t * handle, const char *name, sepol_iface_key_t ** key_ptr) { sepol_iface_key_t *tmp_key = (sepol_iface_key_t *) malloc(sizeof(sepol_iface_key_t)); if (!tmp_key) { ERR(handle, "out of memory, could not create interface key"); return STATUS_ERR; } tmp_key->name = name; *key_ptr = tmp_key; return STATUS_SUCCESS; } hidden_def(sepol_iface_key_create) void sepol_iface_key_unpack(const sepol_iface_key_t * key, const char **name) { *name = key->name; } hidden_def(sepol_iface_key_unpack) int sepol_iface_key_extract(sepol_handle_t * handle, const sepol_iface_t * iface, sepol_iface_key_t ** key_ptr) { if (sepol_iface_key_create(handle, iface->name, key_ptr) < 0) { ERR(handle, "could not extract key from " "interface %s", iface->name); return STATUS_ERR; } return STATUS_SUCCESS; } void sepol_iface_key_free(sepol_iface_key_t * key) { free(key); } int sepol_iface_compare(const sepol_iface_t * iface, const sepol_iface_key_t * key) { return strcmp(iface->name, key->name); } int sepol_iface_compare2(const sepol_iface_t * iface, const sepol_iface_t * iface2) { return strcmp(iface->name, iface2->name); } /* Create */ int sepol_iface_create(sepol_handle_t * handle, sepol_iface_t ** iface) { sepol_iface_t *tmp_iface = (sepol_iface_t *) malloc(sizeof(sepol_iface_t)); if (!tmp_iface) { ERR(handle, "out of memory, could not create " "interface record"); return STATUS_ERR; } tmp_iface->name = NULL; tmp_iface->netif_con = NULL; tmp_iface->netmsg_con = NULL; *iface = tmp_iface; return STATUS_SUCCESS; } hidden_def(sepol_iface_create) /* Name */ const char *sepol_iface_get_name(const sepol_iface_t * iface) { return iface->name; } hidden_def(sepol_iface_get_name) int sepol_iface_set_name(sepol_handle_t * handle, sepol_iface_t * iface, const char *name) { char *tmp_name = strdup(name); if (!tmp_name) { ERR(handle, "out of memory, " "could not set interface name"); return STATUS_ERR; } free(iface->name); iface->name = tmp_name; return STATUS_SUCCESS; } hidden_def(sepol_iface_set_name) /* Interface Context */ sepol_context_t *sepol_iface_get_ifcon(const sepol_iface_t * iface) { return iface->netif_con; } hidden_def(sepol_iface_get_ifcon) int sepol_iface_set_ifcon(sepol_handle_t * handle, sepol_iface_t * iface, sepol_context_t * con) { sepol_context_t *newcon; if (sepol_context_clone(handle, con, &newcon) < 0) { ERR(handle, "out of memory, could not set interface context"); return STATUS_ERR; } sepol_context_free(iface->netif_con); iface->netif_con = newcon; return STATUS_SUCCESS; } hidden_def(sepol_iface_set_ifcon) /* Message Context */ sepol_context_t *sepol_iface_get_msgcon(const sepol_iface_t * iface) { return iface->netmsg_con; } hidden_def(sepol_iface_get_msgcon) int sepol_iface_set_msgcon(sepol_handle_t * handle, sepol_iface_t * iface, sepol_context_t * con) { sepol_context_t *newcon; if (sepol_context_clone(handle, con, &newcon) < 0) { ERR(handle, "out of memory, could not set message context"); return STATUS_ERR; } sepol_context_free(iface->netmsg_con); iface->netmsg_con = newcon; return STATUS_SUCCESS; } hidden_def(sepol_iface_set_msgcon) /* Deep copy clone */ int sepol_iface_clone(sepol_handle_t * handle, const sepol_iface_t * iface, sepol_iface_t ** iface_ptr) { sepol_iface_t *new_iface = NULL; if (sepol_iface_create(handle, &new_iface) < 0) goto err; if (sepol_iface_set_name(handle, new_iface, iface->name) < 0) goto err; if (iface->netif_con && (sepol_context_clone (handle, iface->netif_con, &new_iface->netif_con) < 0)) goto err; if (iface->netmsg_con && (sepol_context_clone (handle, iface->netmsg_con, &new_iface->netmsg_con) < 0)) goto err; *iface_ptr = new_iface; return STATUS_SUCCESS; err: ERR(handle, "could not clone interface record"); sepol_iface_free(new_iface); return STATUS_ERR; } /* Destroy */ void sepol_iface_free(sepol_iface_t * iface) { if (!iface) return; free(iface->name); sepol_context_free(iface->netif_con); sepol_context_free(iface->netmsg_con); free(iface); } hidden_def(sepol_iface_free) libsepol-2.2/src/interfaces.c000066400000000000000000000137321223423440700162530ustar00rootroot00000000000000#include #include "debug.h" #include "context.h" #include "handle.h" #include #include #include "iface_internal.h" /* Create a low level structure from record */ static int iface_from_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t ** iface, const sepol_iface_t * record) { ocontext_t *tmp_iface = NULL; context_struct_t *tmp_con = NULL; tmp_iface = (ocontext_t *) calloc(1, sizeof(ocontext_t)); if (!tmp_iface) goto omem; /* Name */ tmp_iface->u.name = strdup(sepol_iface_get_name(record)); if (!tmp_iface->u.name) goto omem; /* Interface Context */ if (context_from_record(handle, policydb, &tmp_con, sepol_iface_get_ifcon(record)) < 0) goto err; context_cpy(&tmp_iface->context[0], tmp_con); context_destroy(tmp_con); free(tmp_con); tmp_con = NULL; /* Message Context */ if (context_from_record(handle, policydb, &tmp_con, sepol_iface_get_msgcon(record)) < 0) goto err; context_cpy(&tmp_iface->context[1], tmp_con); context_destroy(tmp_con); free(tmp_con); tmp_con = NULL; *iface = tmp_iface; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: if (tmp_iface != NULL) { free(tmp_iface->u.name); context_destroy(&tmp_iface->context[0]); context_destroy(&tmp_iface->context[1]); free(tmp_iface); } context_destroy(tmp_con); free(tmp_con); ERR(handle, "error creating interface structure"); return STATUS_ERR; } static int iface_to_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t * iface, sepol_iface_t ** record) { char *name = iface->u.name; context_struct_t *ifcon = &iface->context[0]; context_struct_t *msgcon = &iface->context[1]; sepol_context_t *tmp_con = NULL; sepol_iface_t *tmp_record = NULL; if (sepol_iface_create(handle, &tmp_record) < 0) goto err; if (sepol_iface_set_name(handle, tmp_record, name) < 0) goto err; if (context_to_record(handle, policydb, ifcon, &tmp_con) < 0) goto err; if (sepol_iface_set_ifcon(handle, tmp_record, tmp_con) < 0) goto err; sepol_context_free(tmp_con); tmp_con = NULL; if (context_to_record(handle, policydb, msgcon, &tmp_con) < 0) goto err; if (sepol_iface_set_msgcon(handle, tmp_record, tmp_con) < 0) goto err; sepol_context_free(tmp_con); tmp_con = NULL; *record = tmp_record; return STATUS_SUCCESS; err: ERR(handle, "could not convert interface %s to record", name); sepol_context_free(tmp_con); sepol_iface_free(tmp_record); return STATUS_ERR; } /* Check if an interface exists */ int sepol_iface_exists(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, const sepol_iface_key_t * key, int *response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; const char *name; sepol_iface_key_unpack(key, &name); head = policydb->ocontexts[OCON_NETIF]; for (c = head; c; c = c->next) { if (!strcmp(name, c->u.name)) { *response = 1; return STATUS_SUCCESS; } } *response = 0; handle = NULL; return STATUS_SUCCESS; } /* Query an interface */ int sepol_iface_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_iface_key_t * key, sepol_iface_t ** response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; const char *name; sepol_iface_key_unpack(key, &name); head = policydb->ocontexts[OCON_NETIF]; for (c = head; c; c = c->next) { if (!strcmp(name, c->u.name)) { if (iface_to_record(handle, policydb, c, response) < 0) goto err; return STATUS_SUCCESS; } } *response = NULL; return STATUS_SUCCESS; err: ERR(handle, "could not query interface %s", name); return STATUS_ERR; } /* Load an interface into policy */ int sepol_iface_modify(sepol_handle_t * handle, sepol_policydb_t * p, const sepol_iface_key_t * key, const sepol_iface_t * data) { policydb_t *policydb = &p->p; ocontext_t *head, *prev, *c, *iface = NULL; const char *name; sepol_iface_key_unpack(key, &name); if (iface_from_record(handle, policydb, &iface, data) < 0) goto err; prev = NULL; head = policydb->ocontexts[OCON_NETIF]; for (c = head; c; c = c->next) { if (!strcmp(name, c->u.name)) { /* Replace */ iface->next = c->next; if (prev == NULL) policydb->ocontexts[OCON_NETIF] = iface; else prev->next = iface; free(c->u.name); context_destroy(&c->context[0]); context_destroy(&c->context[1]); free(c); return STATUS_SUCCESS; } prev = c; } /* Attach to context list */ iface->next = policydb->ocontexts[OCON_NETIF]; policydb->ocontexts[OCON_NETIF] = iface; return STATUS_SUCCESS; err: ERR(handle, "error while loading interface %s", name); if (iface != NULL) { free(iface->u.name); context_destroy(&iface->context[0]); context_destroy(&iface->context[1]); free(iface); } return STATUS_ERR; } /* Return the number of interfaces */ extern int sepol_iface_count(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, unsigned int *response) { unsigned int count = 0; ocontext_t *c, *head; const policydb_t *policydb = &p->p; head = policydb->ocontexts[OCON_NETIF]; for (c = head; c != NULL; c = c->next) count++; *response = count; handle = NULL; return STATUS_SUCCESS; } int sepol_iface_iterate(sepol_handle_t * handle, const sepol_policydb_t * p, int (*fn) (const sepol_iface_t * iface, void *fn_arg), void *arg) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; sepol_iface_t *iface = NULL; head = policydb->ocontexts[OCON_NETIF]; for (c = head; c; c = c->next) { int status; if (iface_to_record(handle, policydb, c, &iface) < 0) goto err; /* Invoke handler */ status = fn(iface, arg); if (status < 0) goto err; sepol_iface_free(iface); iface = NULL; /* Handler requested exit */ if (status > 0) break; } return STATUS_SUCCESS; err: ERR(handle, "could not iterate over interfaces"); sepol_iface_free(iface); return STATUS_ERR; } libsepol-2.2/src/libsepol.map000066400000000000000000000011431223423440700162650ustar00rootroot00000000000000{ global: expand_module_avrules; sepol_module_package_*; sepol_link_modules; sepol_expand_module; sepol_link_packages; sepol_bool_*; sepol_genbools*; sepol_context_*; sepol_mls_*; sepol_check_context; sepol_iface_*; sepol_port_*; sepol_node_*; sepol_user_*; sepol_genusers; sepol_set_delusers; sepol_msg_*; sepol_debug; sepol_handle_*; sepol_policydb_*; sepol_set_policydb_from_file; sepol_policy_kern_*; sepol_policy_file_*; sepol_get_disable_dontaudit; sepol_set_disable_dontaudit; sepol_set_expand_consume_base; sepol_get_preserve_tunables; sepol_set_preserve_tunables; local: *; }; libsepol-2.2/src/libsepol.pc.in000066400000000000000000000004001223423440700165120ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=${prefix} libdir=${exec_prefix}/@libdir@ includedir=@includedir@ Name: libsepol Description: SELinux policy library Version: @VERSION@ URL: http://userspace.selinuxproject.org/ Libs: -L${libdir} -lsepol Cflags: -I${includedir} libsepol-2.2/src/link.c000066400000000000000000002133471223423440700150710ustar00rootroot00000000000000/* Authors: Karl MacMillan * Joshua Brindle * Jason Tang * * Copyright (C) 2004-2005 Tresys Technology, LLC * Copyright (C) 2007 Red Hat, Inc. * * 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 #include #include #include #include #include #include #include #include #include #include #include "debug.h" #undef min #define min(a,b) (((a) < (b)) ? (a) : (b)) typedef struct policy_module { policydb_t *policy; uint32_t num_decls; uint32_t *map[SYM_NUM]; uint32_t *avdecl_map; uint32_t **perm_map; uint32_t *perm_map_len; /* a pointer to within the base module's avrule_block chain to * where this module's global now resides */ avrule_block_t *base_global; } policy_module_t; typedef struct link_state { int verbose; policydb_t *base; avrule_block_t *last_avrule_block, *last_base_avrule_block; uint32_t next_decl_id, current_decl_id; /* temporary variables, used during hashtab_map() calls */ policy_module_t *cur; char *cur_mod_name; avrule_decl_t *dest_decl; class_datum_t *src_class, *dest_class; char *dest_class_name; char dest_class_req; /* flag indicating the class was not declared */ uint32_t symbol_num; /* used to report the name of the module if dependancy error occurs */ policydb_t **decl_to_mod; /* error reporting fields */ sepol_handle_t *handle; } link_state_t; typedef struct missing_requirement { uint32_t symbol_type; uint32_t symbol_value; uint32_t perm_value; } missing_requirement_t; static const char *symtab_names[SYM_NUM] = { "common", "class", "role", "type/attribute", "user", "bool", "level", "category" }; /* Deallocates all elements within a module, but NOT the policydb_t * structure within, as well as the pointer itself. */ static void policy_module_destroy(policy_module_t * mod) { unsigned int i; if (mod == NULL) { return; } for (i = 0; i < SYM_NUM; i++) { free(mod->map[i]); } for (i = 0; mod->perm_map != NULL && i < mod->policy->p_classes.nprim; i++) { free(mod->perm_map[i]); } free(mod->perm_map); free(mod->perm_map_len); free(mod->avdecl_map); free(mod); } /***** functions that copy identifiers from a module to base *****/ /* Note: there is currently no scoping for permissions, which causes some * strange side-effects. The current approach is this: * * a) perm is required and the class _and_ perm are declared in base: only add a mapping. * b) perm is required and the class and perm are _not_ declared in base: simply add the permissions * to the object class. This means that the requirements for the decl are the union of the permissions * required for all decls, but who cares. * c) perm is required, the class is declared in base, but the perm is not present. Nothing we can do * here because we can't mark a single permission as required, so we bail with a requirement error * _even_ if we are in an optional. * * A is correct behavior, b is wrong but not too bad, c is totall wrong for optionals. Fixing this requires * a format change. */ static int permission_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *perm_id = key, *new_id = NULL; perm_datum_t *perm, *new_perm = NULL, *dest_perm; link_state_t *state = (link_state_t *) data; class_datum_t *src_class = state->src_class; class_datum_t *dest_class = state->dest_class; policy_module_t *mod = state->cur; uint32_t sclassi = src_class->s.value - 1; int ret; perm = (perm_datum_t *) datum; dest_perm = hashtab_search(dest_class->permissions.table, perm_id); if (dest_perm == NULL && dest_class->comdatum != NULL) { dest_perm = hashtab_search(dest_class->comdatum->permissions.table, perm_id); } if (dest_perm == NULL) { /* If the object class was not declared in the base, add the perm * to the object class. */ if (state->dest_class_req) { /* If the class was required (not declared), insert the new permission */ new_id = strdup(perm_id); if (new_id == NULL) { ERR(state->handle, "Memory error"); ret = SEPOL_ERR; goto err; } new_perm = (perm_datum_t *) calloc(1, sizeof(perm_datum_t)); if (new_perm == NULL) { ERR(state->handle, "Memory error"); ret = SEPOL_ERR; goto err; } ret = hashtab_insert(dest_class->permissions.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_perm); if (ret) { ERR(state->handle, "could not insert permission into class\n"); goto err; } new_perm->s.value = dest_class->permissions.nprim + 1; dest_perm = new_perm; } else { /* this is case c from above */ ERR(state->handle, "Module %s depends on permission %s in class %s, not satisfied", state->cur_mod_name, perm_id, state->dest_class_name); return SEPOL_EREQ; } } /* build the mapping for permissions encompassing this class. * unlike symbols, the permission map translates between * module permission bit to target permission bit. that bit * may have originated from the class -or- it could be from * the class's common parent.*/ if (perm->s.value > mod->perm_map_len[sclassi]) { uint32_t *newmap = calloc(perm->s.value, sizeof(*newmap)); if (newmap == NULL) { ERR(state->handle, "Out of memory!"); return -1; } memcpy(newmap, mod->perm_map[sclassi], mod->perm_map_len[sclassi] * sizeof(*newmap)); free(mod->perm_map[sclassi]); mod->perm_map[sclassi] = newmap; mod->perm_map_len[sclassi] = perm->s.value; } mod->perm_map[sclassi][perm->s.value - 1] = dest_perm->s.value; return 0; err: free(new_id); free(new_perm); return ret; } static int class_copy_default_new_object(link_state_t *state, class_datum_t *olddatum, class_datum_t *newdatum) { if (olddatum->default_user) { if (newdatum->default_user && olddatum->default_user != newdatum->default_user) { ERR(state->handle, "Found conflicting default user definitions"); return SEPOL_ENOTSUP; } newdatum->default_user = olddatum->default_user; } if (olddatum->default_role) { if (newdatum->default_role && olddatum->default_role != newdatum->default_role) { ERR(state->handle, "Found conflicting default role definitions"); return SEPOL_ENOTSUP; } newdatum->default_role = olddatum->default_role; } if (olddatum->default_type) { if (newdatum->default_type && olddatum->default_type != newdatum->default_type) { ERR(state->handle, "Found conflicting default type definitions"); return SEPOL_ENOTSUP; } newdatum->default_type = olddatum->default_type; } if (olddatum->default_range) { if (newdatum->default_range && olddatum->default_range != newdatum->default_range) { ERR(state->handle, "Found conflicting default range definitions"); return SEPOL_ENOTSUP; } newdatum->default_range = olddatum->default_range; } return 0; } static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key, *new_id = NULL; class_datum_t *cladatum, *new_class = NULL; link_state_t *state = (link_state_t *) data; scope_datum_t *scope = NULL; int ret; cladatum = (class_datum_t *) datum; state->dest_class_req = 0; new_class = hashtab_search(state->base->p_classes.table, id); /* If there is not an object class already in the base symtab that means * that either a) a module is trying to declare a new object class (which * the compiler should prevent) or b) an object class was required that is * not in the base. */ if (new_class == NULL) { scope = hashtab_search(state->cur->policy->p_classes_scope.table, id); if (scope == NULL) { ret = SEPOL_ERR; goto err; } if (scope->scope == SCOPE_DECL) { /* disallow declarations in modules */ ERR(state->handle, "%s: Modules may not yet declare new classes.", state->cur_mod_name); ret = SEPOL_ENOTSUP; goto err; } else { /* It would be nice to error early here because the requirement is * not met, but we cannot because the decl might be optional (in which * case we should record the requirement so that it is just turned * off). Note: this will break horribly if modules can declare object * classes because the class numbers will be all wrong (i.e., they * might be assigned in the order they were required rather than the * current scheme which ensures correct numbering by ordering the * declarations properly). This can't be fixed until some infrastructure * for querying the object class numbers is in place. */ state->dest_class_req = 1; new_class = (class_datum_t *) calloc(1, sizeof(class_datum_t)); if (new_class == NULL) { ERR(state->handle, "Memory error\n"); ret = SEPOL_ERR; goto err; } if (symtab_init (&new_class->permissions, PERM_SYMTAB_SIZE)) { ret = SEPOL_ERR; goto err; } new_id = strdup(id); if (new_id == NULL) { ERR(state->handle, "Memory error\n"); symtab_destroy(&new_class->permissions); ret = SEPOL_ERR; goto err; } ret = hashtab_insert(state->base->p_classes.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_class); if (ret) { ERR(state->handle, "could not insert new class into symtab"); symtab_destroy(&new_class->permissions); goto err; } new_class->s.value = ++(state->base->p_classes.nprim); } } state->cur->map[SYM_CLASSES][cladatum->s.value - 1] = new_class->s.value; /* copy permissions */ state->src_class = cladatum; state->dest_class = new_class; state->dest_class_name = (char *)key; /* copy default new object rules */ ret = class_copy_default_new_object(state, cladatum, new_class); if (ret) return ret; ret = hashtab_map(cladatum->permissions.table, permission_copy_callback, state); if (ret != 0) { return ret; } return 0; err: free(new_class); free(new_id); return ret; } static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id = key, *new_id = NULL; role_datum_t *role, *base_role, *new_role = NULL; link_state_t *state = (link_state_t *) data; role = (role_datum_t *) datum; base_role = hashtab_search(state->base->p_roles.table, id); if (base_role != NULL) { /* role already exists. check that it is what this * module expected. duplicate declarations (e.g., two * modules both declare role foo_r) is checked during * scope_copy_callback(). */ if (role->flavor == ROLE_ATTRIB && base_role->flavor != ROLE_ATTRIB) { ERR(state->handle, "%s: Expected %s to be a role attribute, but it was already declared as a regular role.", state->cur_mod_name, id); return -1; } else if (role->flavor != ROLE_ATTRIB && base_role->flavor == ROLE_ATTRIB) { ERR(state->handle, "%s: Expected %s to be a regular role, but it was already declared as a role attribute.", state->cur_mod_name, id); return -1; } } else { if (state->verbose) INFO(state->handle, "copying role %s", id); if ((new_id = strdup(id)) == NULL) { goto cleanup; } if ((new_role = (role_datum_t *) malloc(sizeof(*new_role))) == NULL) { goto cleanup; } role_datum_init(new_role); /* new_role's dominates, types and roles field will be copied * during role_fix_callback() */ new_role->flavor = role->flavor; new_role->s.value = state->base->p_roles.nprim + 1; ret = hashtab_insert(state->base->p_roles.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_role); if (ret) { goto cleanup; } state->base->p_roles.nprim++; base_role = new_role; } if (state->dest_decl) { new_id = NULL; if ((new_role = malloc(sizeof(*new_role))) == NULL) { goto cleanup; } role_datum_init(new_role); new_role->flavor = base_role->flavor; new_role->s.value = base_role->s.value; if ((new_id = strdup(id)) == NULL) { goto cleanup; } if (hashtab_insert (state->dest_decl->p_roles.table, new_id, new_role)) { goto cleanup; } state->dest_decl->p_roles.nprim++; } state->cur->map[SYM_ROLES][role->s.value - 1] = base_role->s.value; return 0; cleanup: ERR(state->handle, "Out of memory!"); role_datum_destroy(new_role); free(new_id); free(new_role); return -1; } /* Copy types and attributes from a module into the base module. The * attributes are copied, but the types that make up this attribute * are delayed type_fix_callback(). */ static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id = key, *new_id = NULL; type_datum_t *type, *base_type, *new_type = NULL; link_state_t *state = (link_state_t *) data; type = (type_datum_t *) datum; if ((type->flavor == TYPE_TYPE && !type->primary) || type->flavor == TYPE_ALIAS) { /* aliases are handled later, in alias_copy_callback() */ return 0; } base_type = hashtab_search(state->base->p_types.table, id); if (base_type != NULL) { /* type already exists. check that it is what this * module expected. duplicate declarations (e.g., two * modules both declare type foo_t) is checked during * scope_copy_callback(). */ if (type->flavor == TYPE_ATTRIB && base_type->flavor != TYPE_ATTRIB) { ERR(state->handle, "%s: Expected %s to be an attribute, but it was already declared as a type.", state->cur_mod_name, id); return -1; } else if (type->flavor != TYPE_ATTRIB && base_type->flavor == TYPE_ATTRIB) { ERR(state->handle, "%s: Expected %s to be a type, but it was already declared as an attribute.", state->cur_mod_name, id); return -1; } /* permissive should pass to the base type */ base_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE); } else { if (state->verbose) INFO(state->handle, "copying type %s", id); if ((new_id = strdup(id)) == NULL) { goto cleanup; } if ((new_type = (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) { goto cleanup; } new_type->primary = type->primary; new_type->flags = type->flags; new_type->flavor = type->flavor; /* for attributes, the writing of new_type->types is done in type_fix_callback() */ new_type->s.value = state->base->p_types.nprim + 1; ret = hashtab_insert(state->base->p_types.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_type); if (ret) { goto cleanup; } state->base->p_types.nprim++; base_type = new_type; } if (state->dest_decl) { new_id = NULL; if ((new_type = calloc(1, sizeof(*new_type))) == NULL) { goto cleanup; } new_type->primary = type->primary; new_type->flavor = type->flavor; new_type->flags = type->flags; new_type->s.value = base_type->s.value; if ((new_id = strdup(id)) == NULL) { goto cleanup; } if (hashtab_insert (state->dest_decl->p_types.table, new_id, new_type)) { goto cleanup; } state->dest_decl->p_types.nprim++; } state->cur->map[SYM_TYPES][type->s.value - 1] = base_type->s.value; return 0; cleanup: ERR(state->handle, "Out of memory!"); free(new_id); free(new_type); return -1; } static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id = key, *new_id = NULL; user_datum_t *user, *base_user, *new_user = NULL; link_state_t *state = (link_state_t *) data; user = (user_datum_t *) datum; base_user = hashtab_search(state->base->p_users.table, id); if (base_user == NULL) { if (state->verbose) INFO(state->handle, "copying user %s", id); if ((new_id = strdup(id)) == NULL) { goto cleanup; } if ((new_user = (user_datum_t *) malloc(sizeof(*new_user))) == NULL) { goto cleanup; } user_datum_init(new_user); /* new_users's roles and MLS fields will be copied during user_fix_callback(). */ new_user->s.value = state->base->p_users.nprim + 1; ret = hashtab_insert(state->base->p_users.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_user); if (ret) { goto cleanup; } state->base->p_users.nprim++; base_user = new_user; } if (state->dest_decl) { new_id = NULL; if ((new_user = malloc(sizeof(*new_user))) == NULL) { goto cleanup; } user_datum_init(new_user); new_user->s.value = base_user->s.value; if ((new_id = strdup(id)) == NULL) { goto cleanup; } if (hashtab_insert (state->dest_decl->p_users.table, new_id, new_user)) { goto cleanup; } state->dest_decl->p_users.nprim++; } state->cur->map[SYM_USERS][user->s.value - 1] = base_user->s.value; return 0; cleanup: ERR(state->handle, "Out of memory!"); user_datum_destroy(new_user); free(new_id); free(new_user); return -1; } static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { int ret; char *id = key, *new_id = NULL; cond_bool_datum_t *booldatum, *base_bool, *new_bool = NULL; link_state_t *state = (link_state_t *) data; scope_datum_t *scope; booldatum = (cond_bool_datum_t *) datum; base_bool = hashtab_search(state->base->p_bools.table, id); if (base_bool == NULL) { if (state->verbose) INFO(state->handle, "copying boolean %s", id); if ((new_id = strdup(id)) == NULL) { goto cleanup; } if ((new_bool = (cond_bool_datum_t *) malloc(sizeof(*new_bool))) == NULL) { goto cleanup; } new_bool->s.value = state->base->p_bools.nprim + 1; ret = hashtab_insert(state->base->p_bools.table, (hashtab_key_t) new_id, (hashtab_datum_t) new_bool); if (ret) { goto cleanup; } state->base->p_bools.nprim++; base_bool = new_bool; base_bool->flags = booldatum->flags; } else if ((booldatum->flags & COND_BOOL_FLAGS_TUNABLE) != (base_bool->flags & COND_BOOL_FLAGS_TUNABLE)) { /* A mismatch between boolean/tunable declaration * and usage(for example a boolean used in the * tunable_policy() or vice versa). * * This is not allowed and bail out with errors */ ERR(state->handle, "%s: Mismatch between boolean/tunable definition " "and usage for %s", state->cur_mod_name, id); return -1; } /* Get the scope info for this boolean to see if this is the declaration, * if so set the state */ scope = hashtab_search(state->cur->policy->p_bools_scope.table, id); if (!scope) return SEPOL_ERR; if (scope->scope == SCOPE_DECL) { base_bool->state = booldatum->state; /* Only the declaration rather than requirement * decides if it is a boolean or tunable. */ base_bool->flags = booldatum->flags; } state->cur->map[SYM_BOOLS][booldatum->s.value - 1] = base_bool->s.value; return 0; cleanup: ERR(state->handle, "Out of memory!"); cond_destroy_bool(new_id, new_bool, NULL); return -1; } static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key; level_datum_t *level, *base_level; link_state_t *state = (link_state_t *) data; scope_datum_t *scope; level = (level_datum_t *) datum; base_level = hashtab_search(state->base->p_levels.table, id); if (!base_level) { scope = hashtab_search(state->cur->policy->p_sens_scope.table, id); if (!scope) return SEPOL_ERR; if (scope->scope == SCOPE_DECL) { /* disallow declarations in modules */ ERR(state->handle, "%s: Modules may not declare new sensitivities.", state->cur_mod_name); return SEPOL_ENOTSUP; } else if (scope->scope == SCOPE_REQ) { /* unmet requirement */ ERR(state->handle, "%s: Sensitivity %s not declared by base.", state->cur_mod_name, id); return SEPOL_ENOTSUP; } else { ERR(state->handle, "%s: has an unknown scope: %d\n", state->cur_mod_name, scope->scope); return SEPOL_ENOTSUP; } } state->cur->map[SYM_LEVELS][level->level->sens - 1] = base_level->level->sens; return 0; } static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key; cat_datum_t *cat, *base_cat; link_state_t *state = (link_state_t *) data; scope_datum_t *scope; cat = (cat_datum_t *) datum; base_cat = hashtab_search(state->base->p_cats.table, id); if (!base_cat) { scope = hashtab_search(state->cur->policy->p_cat_scope.table, id); if (!scope) return SEPOL_ERR; if (scope->scope == SCOPE_DECL) { /* disallow declarations in modules */ ERR(state->handle, "%s: Modules may not declare new categories.", state->cur_mod_name); return SEPOL_ENOTSUP; } else if (scope->scope == SCOPE_REQ) { /* unmet requirement */ ERR(state->handle, "%s: Category %s not declared by base.", state->cur_mod_name, id); return SEPOL_ENOTSUP; } else { /* unknown scope? malformed policy? */ ERR(state->handle, "%s: has an unknown scope: %d\n", state->cur_mod_name, scope->scope); return SEPOL_ENOTSUP; } } state->cur->map[SYM_CATS][cat->s.value - 1] = base_cat->s.value; return 0; } static int (*copy_callback_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) = { NULL, class_copy_callback, role_copy_callback, type_copy_callback, user_copy_callback, bool_copy_callback, sens_copy_callback, cat_copy_callback}; /* * The boundaries have to be copied after the types/roles/users are copied, * because it refers hashtab to lookup destinated objects. */ static int type_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { link_state_t *state = (link_state_t *) data; type_datum_t *type = (type_datum_t *) datum; type_datum_t *dest; uint32_t bounds_val; if (!type->bounds) return 0; bounds_val = state->cur->map[SYM_TYPES][type->bounds - 1]; dest = hashtab_search(state->base->p_types.table, key); if (!dest) { ERR(state->handle, "Type lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } static int role_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { link_state_t *state = (link_state_t *) data; role_datum_t *role = (role_datum_t *) datum; role_datum_t *dest; uint32_t bounds_val; if (!role->bounds) return 0; bounds_val = state->cur->map[SYM_ROLES][role->bounds - 1]; dest = hashtab_search(state->base->p_roles.table, key); if (!dest) { ERR(state->handle, "Role lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } static int user_bounds_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { link_state_t *state = (link_state_t *) data; user_datum_t *user = (user_datum_t *) datum; user_datum_t *dest; uint32_t bounds_val; if (!user->bounds) return 0; bounds_val = state->cur->map[SYM_USERS][user->bounds - 1]; dest = hashtab_search(state->base->p_users.table, key); if (!dest) { ERR(state->handle, "User lookup failed for %s", (char *)key); return -1; } if (dest->bounds != 0 && dest->bounds != bounds_val) { ERR(state->handle, "Inconsistent boundary for %s", (char *)key); return -1; } dest->bounds = bounds_val; return 0; } /* The aliases have to be copied after the types and attributes to be * certain that the base symbol table will have the type that the * alias refers. Otherwise, we won't be able to find the type value * for the alias. We can't depend on the declaration ordering because * of the hash table. */ static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key, *new_id = NULL, *target_id; type_datum_t *type, *base_type, *new_type = NULL, *target_type; link_state_t *state = (link_state_t *) data; policy_module_t *mod = state->cur; int primval; type = (type_datum_t *) datum; /* there are 2 kinds of aliases. Ones with their own value (TYPE_ALIAS) * and ones with the value of their primary (TYPE_TYPE && type->primary = 0) */ if (! (type->flavor == TYPE_ALIAS || (type->flavor == TYPE_TYPE && !type->primary))) { /* ignore types and attributes -- they were handled in * type_copy_callback() */ return 0; } if (type->flavor == TYPE_ALIAS) primval = type->primary; else primval = type->s.value; target_id = mod->policy->p_type_val_to_name[primval - 1]; target_type = hashtab_search(state->base->p_types.table, target_id); if (target_type == NULL) { ERR(state->handle, "%s: Could not find type %s for alias %s.", state->cur_mod_name, target_id, id); return -1; } if (!strcmp(id, target_id)) { ERR(state->handle, "%s: Self aliasing of %s.", state->cur_mod_name, id); return -1; } target_type->flags |= (type->flags & TYPE_FLAGS_PERMISSIVE); base_type = hashtab_search(state->base->p_types.table, id); if (base_type == NULL) { if (state->verbose) INFO(state->handle, "copying alias %s", id); if ((new_type = (type_datum_t *) calloc(1, sizeof(*new_type))) == NULL) { goto cleanup; } /* the linked copy always has TYPE_ALIAS style aliases */ new_type->primary = target_type->s.value; new_type->flags = target_type->flags; new_type->flavor = TYPE_ALIAS; new_type->s.value = state->base->p_types.nprim + 1; if ((new_id = strdup(id)) == NULL) { goto cleanup; } if (hashtab_insert (state->base->p_types.table, new_id, new_type)) { goto cleanup; } state->base->p_types.nprim++; base_type = new_type; } else { /* if this already exists and isn't an alias it was required by another module (or base) * and inserted into the hashtable as a type, fix it up now */ if (base_type->flavor == TYPE_ALIAS) { /* error checking */ assert(base_type->primary == target_type->s.value); assert(base_type->primary == mod->map[SYM_TYPES][primval - 1]); assert(mod->map[SYM_TYPES][type->s.value - 1] == base_type->primary); return 0; } if (base_type->flavor == TYPE_ATTRIB) { ERR(state->handle, "%s is an alias of an attribute, not allowed", id); return -1; } base_type->flavor = TYPE_ALIAS; base_type->primary = target_type->s.value; base_type->flags |= (target_type->flags & TYPE_FLAGS_PERMISSIVE); } /* the aliases map points from its value to its primary so when this module * references this type the value it gets back from the map is the primary */ mod->map[SYM_TYPES][type->s.value - 1] = base_type->primary; return 0; cleanup: ERR(state->handle, "Out of memory!"); free(new_id); free(new_type); return -1; } /*********** callbacks that fix bitmaps ***********/ static int type_set_convert(type_set_t * types, type_set_t * dst, policy_module_t * mod, link_state_t * state __attribute__ ((unused))) { unsigned int i; ebitmap_node_t *tnode; ebitmap_for_each_bit(&types->types, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { assert(mod->map[SYM_TYPES][i]); if (ebitmap_set_bit (&dst->types, mod->map[SYM_TYPES][i] - 1, 1)) { goto cleanup; } } } ebitmap_for_each_bit(&types->negset, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { assert(mod->map[SYM_TYPES][i]); if (ebitmap_set_bit (&dst->negset, mod->map[SYM_TYPES][i] - 1, 1)) { goto cleanup; } } } dst->flags = types->flags; return 0; cleanup: return -1; } /* OR 2 typemaps together and at the same time map the src types to * the correct values in the dst typeset. */ static int type_set_or_convert(type_set_t * types, type_set_t * dst, policy_module_t * mod, link_state_t * state) { type_set_t ts_tmp; type_set_init(&ts_tmp); if (type_set_convert(types, &ts_tmp, mod, state) == -1) { goto cleanup; } if (type_set_or_eq(dst, &ts_tmp)) { goto cleanup; } type_set_destroy(&ts_tmp); return 0; cleanup: ERR(state->handle, "Out of memory!"); type_set_destroy(&ts_tmp); return -1; } static int role_set_or_convert(role_set_t * roles, role_set_t * dst, policy_module_t * mod, link_state_t * state) { unsigned int i; ebitmap_t tmp; ebitmap_node_t *rnode; ebitmap_init(&tmp); ebitmap_for_each_bit(&roles->roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { assert(mod->map[SYM_ROLES][i]); if (ebitmap_set_bit (&tmp, mod->map[SYM_ROLES][i] - 1, 1)) { goto cleanup; } } } if (ebitmap_union(&dst->roles, &tmp)) { goto cleanup; } dst->flags |= roles->flags; ebitmap_destroy(&tmp); return 0; cleanup: ERR(state->handle, "Out of memory!"); ebitmap_destroy(&tmp); return -1; } static int mls_level_convert(mls_semantic_level_t * src, mls_semantic_level_t * dst, policy_module_t * mod, link_state_t * state) { mls_semantic_cat_t *src_cat, *new_cat; if (!mod->policy->mls) return 0; /* Required not declared. */ if (!src->sens) return 0; assert(mod->map[SYM_LEVELS][src->sens - 1]); dst->sens = mod->map[SYM_LEVELS][src->sens - 1]; for (src_cat = src->cat; src_cat; src_cat = src_cat->next) { new_cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); if (!new_cat) { ERR(state->handle, "Out of memory"); return -1; } mls_semantic_cat_init(new_cat); new_cat->next = dst->cat; dst->cat = new_cat; assert(mod->map[SYM_CATS][src_cat->low - 1]); dst->cat->low = mod->map[SYM_CATS][src_cat->low - 1]; assert(mod->map[SYM_CATS][src_cat->high - 1]); dst->cat->high = mod->map[SYM_CATS][src_cat->high - 1]; } return 0; } static int mls_range_convert(mls_semantic_range_t * src, mls_semantic_range_t * dst, policy_module_t * mod, link_state_t * state) { int ret; ret = mls_level_convert(&src->level[0], &dst->level[0], mod, state); if (ret) return ret; ret = mls_level_convert(&src->level[1], &dst->level[1], mod, state); if (ret) return ret; return 0; } static int role_fix_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { unsigned int i; char *id = key; role_datum_t *role, *dest_role = NULL; link_state_t *state = (link_state_t *) data; ebitmap_t e_tmp; policy_module_t *mod = state->cur; ebitmap_node_t *rnode; hashtab_t role_tab; role = (role_datum_t *) datum; if (state->dest_decl == NULL) role_tab = state->base->p_roles.table; else role_tab = state->dest_decl->p_roles.table; dest_role = hashtab_search(role_tab, id); assert(dest_role != NULL); if (state->verbose) { INFO(state->handle, "fixing role %s", id); } ebitmap_init(&e_tmp); ebitmap_for_each_bit(&role->dominates, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { assert(mod->map[SYM_ROLES][i]); if (ebitmap_set_bit (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) { goto cleanup; } } } if (ebitmap_union(&dest_role->dominates, &e_tmp)) { goto cleanup; } if (type_set_or_convert(&role->types, &dest_role->types, mod, state)) { goto cleanup; } ebitmap_destroy(&e_tmp); if (role->flavor == ROLE_ATTRIB) { ebitmap_init(&e_tmp); ebitmap_for_each_bit(&role->roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { assert(mod->map[SYM_ROLES][i]); if (ebitmap_set_bit (&e_tmp, mod->map[SYM_ROLES][i] - 1, 1)) { goto cleanup; } } } if (ebitmap_union(&dest_role->roles, &e_tmp)) { goto cleanup; } ebitmap_destroy(&e_tmp); } return 0; cleanup: ERR(state->handle, "Out of memory!"); ebitmap_destroy(&e_tmp); return -1; } static int type_fix_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { unsigned int i; char *id = key; type_datum_t *type, *new_type = NULL; link_state_t *state = (link_state_t *) data; ebitmap_t e_tmp; policy_module_t *mod = state->cur; ebitmap_node_t *tnode; symtab_t *typetab; type = (type_datum_t *) datum; if (state->dest_decl == NULL) typetab = &state->base->p_types; else typetab = &state->dest_decl->p_types; /* only fix attributes */ if (type->flavor != TYPE_ATTRIB) { return 0; } new_type = hashtab_search(typetab->table, id); assert(new_type != NULL && new_type->flavor == TYPE_ATTRIB); if (state->verbose) { INFO(state->handle, "fixing attribute %s", id); } ebitmap_init(&e_tmp); ebitmap_for_each_bit(&type->types, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { assert(mod->map[SYM_TYPES][i]); if (ebitmap_set_bit (&e_tmp, mod->map[SYM_TYPES][i] - 1, 1)) { goto cleanup; } } } if (ebitmap_union(&new_type->types, &e_tmp)) { goto cleanup; } ebitmap_destroy(&e_tmp); return 0; cleanup: ERR(state->handle, "Out of memory!"); ebitmap_destroy(&e_tmp); return -1; } static int user_fix_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key; user_datum_t *user, *new_user = NULL; link_state_t *state = (link_state_t *) data; policy_module_t *mod = state->cur; symtab_t *usertab; user = (user_datum_t *) datum; if (state->dest_decl == NULL) usertab = &state->base->p_users; else usertab = &state->dest_decl->p_users; new_user = hashtab_search(usertab->table, id); assert(new_user != NULL); if (state->verbose) { INFO(state->handle, "fixing user %s", id); } if (role_set_or_convert(&user->roles, &new_user->roles, mod, state)) { goto cleanup; } if (mls_range_convert(&user->range, &new_user->range, mod, state)) goto cleanup; if (mls_level_convert(&user->dfltlevel, &new_user->dfltlevel, mod, state)) goto cleanup; return 0; cleanup: ERR(state->handle, "Out of memory!"); return -1; } static int (*fix_callback_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) = { NULL, NULL, role_fix_callback, type_fix_callback, user_fix_callback, NULL, NULL, NULL}; /*********** functions that copy AV rules ***********/ static int copy_avrule_list(avrule_t * list, avrule_t ** dst, policy_module_t * module, link_state_t * state) { unsigned int i; avrule_t *cur, *new_rule = NULL, *tail; class_perm_node_t *cur_perm, *new_perm, *tail_perm = NULL; tail = *dst; while (tail && tail->next) { tail = tail->next; } cur = list; while (cur) { if ((new_rule = (avrule_t *) malloc(sizeof(avrule_t))) == NULL) { goto cleanup; } avrule_init(new_rule); new_rule->specified = cur->specified; new_rule->flags = cur->flags; if (type_set_convert (&cur->stypes, &new_rule->stypes, module, state) == -1 || type_set_convert(&cur->ttypes, &new_rule->ttypes, module, state) == -1) { goto cleanup; } cur_perm = cur->perms; tail_perm = NULL; while (cur_perm) { if ((new_perm = (class_perm_node_t *) malloc(sizeof(class_perm_node_t))) == NULL) { goto cleanup; } class_perm_node_init(new_perm); new_perm->class = module->map[SYM_CLASSES][cur_perm->class - 1]; assert(new_perm->class); if (new_rule->specified & AVRULE_AV) { for (i = 0; i < module->perm_map_len[cur_perm->class - 1]; i++) { if (!(cur_perm->data & (1U << i))) continue; new_perm->data |= (1U << (module-> perm_map[cur_perm->class - 1][i] - 1)); } } else { new_perm->data = module->map[SYM_TYPES][cur_perm->data - 1]; } if (new_rule->perms == NULL) { new_rule->perms = new_perm; } else { assert(tail_perm); tail_perm->next = new_perm; } tail_perm = new_perm; cur_perm = cur_perm->next; } new_rule->line = cur->line; cur = cur->next; if (*dst == NULL) { *dst = new_rule; } else { tail->next = new_rule; } tail = new_rule; } return 0; cleanup: ERR(state->handle, "Out of memory!"); avrule_destroy(new_rule); free(new_rule); return -1; } static int copy_role_trans_list(role_trans_rule_t * list, role_trans_rule_t ** dst, policy_module_t * module, link_state_t * state) { role_trans_rule_t *cur, *new_rule = NULL, *tail; unsigned int i; ebitmap_node_t *cnode; cur = list; tail = *dst; while (tail && tail->next) { tail = tail->next; } while (cur) { if ((new_rule = (role_trans_rule_t *) malloc(sizeof(role_trans_rule_t))) == NULL) { goto cleanup; } role_trans_rule_init(new_rule); if (role_set_or_convert (&cur->roles, &new_rule->roles, module, state) || type_set_or_convert(&cur->types, &new_rule->types, module, state)) { goto cleanup; } ebitmap_for_each_bit(&cur->classes, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { assert(module->map[SYM_CLASSES][i]); if (ebitmap_set_bit(&new_rule->classes, module-> map[SYM_CLASSES][i] - 1, 1)) { goto cleanup; } } } new_rule->new_role = module->map[SYM_ROLES][cur->new_role - 1]; if (*dst == NULL) { *dst = new_rule; } else { tail->next = new_rule; } tail = new_rule; cur = cur->next; } return 0; cleanup: ERR(state->handle, "Out of memory!"); role_trans_rule_list_destroy(new_rule); return -1; } static int copy_role_allow_list(role_allow_rule_t * list, role_allow_rule_t ** dst, policy_module_t * module, link_state_t * state) { role_allow_rule_t *cur, *new_rule = NULL, *tail; cur = list; tail = *dst; while (tail && tail->next) { tail = tail->next; } while (cur) { if ((new_rule = (role_allow_rule_t *) malloc(sizeof(role_allow_rule_t))) == NULL) { goto cleanup; } role_allow_rule_init(new_rule); if (role_set_or_convert (&cur->roles, &new_rule->roles, module, state) || role_set_or_convert(&cur->new_roles, &new_rule->new_roles, module, state)) { goto cleanup; } if (*dst == NULL) { *dst = new_rule; } else { tail->next = new_rule; } tail = new_rule; cur = cur->next; } return 0; cleanup: ERR(state->handle, "Out of memory!"); role_allow_rule_list_destroy(new_rule); return -1; } static int copy_filename_trans_list(filename_trans_rule_t * list, filename_trans_rule_t ** dst, policy_module_t * module, link_state_t * state) { filename_trans_rule_t *cur, *new_rule, *tail; cur = list; tail = *dst; while (tail && tail->next) tail = tail->next; while (cur) { new_rule = malloc(sizeof(*new_rule)); if (!new_rule) goto err; filename_trans_rule_init(new_rule); if (*dst == NULL) *dst = new_rule; else tail->next = new_rule; tail = new_rule; new_rule->name = strdup(cur->name); if (!new_rule->name) goto err; if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module, state) || type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module, state)) goto err; new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1]; new_rule->otype = module->map[SYM_TYPES][cur->otype - 1]; cur = cur->next; } return 0; err: ERR(state->handle, "Out of memory!"); return -1; } static int copy_range_trans_list(range_trans_rule_t * rules, range_trans_rule_t ** dst, policy_module_t * mod, link_state_t * state) { range_trans_rule_t *rule, *new_rule = NULL; unsigned int i; ebitmap_node_t *cnode; for (rule = rules; rule; rule = rule->next) { new_rule = (range_trans_rule_t *) malloc(sizeof(range_trans_rule_t)); if (!new_rule) goto cleanup; range_trans_rule_init(new_rule); new_rule->next = *dst; *dst = new_rule; if (type_set_convert(&rule->stypes, &new_rule->stypes, mod, state)) goto cleanup; if (type_set_convert(&rule->ttypes, &new_rule->ttypes, mod, state)) goto cleanup; ebitmap_for_each_bit(&rule->tclasses, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { assert(mod->map[SYM_CLASSES][i]); if (ebitmap_set_bit (&new_rule->tclasses, mod->map[SYM_CLASSES][i] - 1, 1)) { goto cleanup; } } } if (mls_range_convert(&rule->trange, &new_rule->trange, mod, state)) goto cleanup; } return 0; cleanup: ERR(state->handle, "Out of memory!"); range_trans_rule_list_destroy(new_rule); return -1; } static int copy_cond_list(cond_node_t * list, cond_node_t ** dst, policy_module_t * module, link_state_t * state) { unsigned i; cond_node_t *cur, *new_node = NULL, *tail; cond_expr_t *cur_expr; tail = *dst; while (tail && tail->next) tail = tail->next; cur = list; while (cur) { new_node = (cond_node_t *) malloc(sizeof(cond_node_t)); if (!new_node) { goto cleanup; } memset(new_node, 0, sizeof(cond_node_t)); new_node->cur_state = cur->cur_state; new_node->expr = cond_copy_expr(cur->expr); if (!new_node->expr) goto cleanup; /* go back through and remap the expression */ for (cur_expr = new_node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { /* expression nodes don't have a bool value of 0 - don't map them */ if (cur_expr->expr_type != COND_BOOL) continue; assert(module->map[SYM_BOOLS][cur_expr->bool - 1] != 0); cur_expr->bool = module->map[SYM_BOOLS][cur_expr->bool - 1]; } new_node->nbools = cur->nbools; /* FIXME should COND_MAX_BOOLS be used here? */ for (i = 0; i < min(cur->nbools, COND_MAX_BOOLS); i++) { uint32_t remapped_id = module->map[SYM_BOOLS][cur->bool_ids[i] - 1]; assert(remapped_id != 0); new_node->bool_ids[i] = remapped_id; } new_node->expr_pre_comp = cur->expr_pre_comp; if (copy_avrule_list (cur->avtrue_list, &new_node->avtrue_list, module, state) || copy_avrule_list(cur->avfalse_list, &new_node->avfalse_list, module, state)) { goto cleanup; } if (*dst == NULL) { *dst = new_node; } else { tail->next = new_node; } tail = new_node; cur = cur->next; } return 0; cleanup: ERR(state->handle, "Out of memory!"); cond_node_destroy(new_node); free(new_node); return -1; } /*********** functions that copy avrule_decls from module to base ***********/ static int copy_identifiers(link_state_t * state, symtab_t * src_symtab, avrule_decl_t * dest_decl) { int i, ret; state->dest_decl = dest_decl; for (i = 0; i < SYM_NUM; i++) { if (copy_callback_f[i] != NULL) { ret = hashtab_map(src_symtab[i].table, copy_callback_f[i], state); if (ret) { return ret; } } } if (hashtab_map(src_symtab[SYM_TYPES].table, type_bounds_copy_callback, state)) return -1; if (hashtab_map(src_symtab[SYM_TYPES].table, alias_copy_callback, state)) return -1; if (hashtab_map(src_symtab[SYM_ROLES].table, role_bounds_copy_callback, state)) return -1; if (hashtab_map(src_symtab[SYM_USERS].table, user_bounds_copy_callback, state)) return -1; /* then fix bitmaps associated with those newly copied identifiers */ for (i = 0; i < SYM_NUM; i++) { if (fix_callback_f[i] != NULL && hashtab_map(src_symtab[i].table, fix_callback_f[i], state)) { return -1; } } return 0; } static int copy_scope_index(scope_index_t * src, scope_index_t * dest, policy_module_t * module, link_state_t * state) { unsigned int i, j; uint32_t largest_mapped_class_value = 0; ebitmap_node_t *node; /* copy the scoping information for this avrule decl block */ for (i = 0; i < SYM_NUM; i++) { ebitmap_t *srcmap = src->scope + i; ebitmap_t *destmap = dest->scope + i; if (copy_callback_f[i] == NULL) { continue; } ebitmap_for_each_bit(srcmap, node, j) { if (ebitmap_node_get_bit(node, j)) { assert(module->map[i][j] != 0); if (ebitmap_set_bit (destmap, module->map[i][j] - 1, 1) != 0) { goto cleanup; } if (i == SYM_CLASSES && largest_mapped_class_value < module->map[SYM_CLASSES][j]) { largest_mapped_class_value = module->map[SYM_CLASSES][j]; } } } } /* next copy the enabled permissions data */ if ((dest->class_perms_map = malloc(largest_mapped_class_value * sizeof(*dest->class_perms_map))) == NULL) { goto cleanup; } for (i = 0; i < largest_mapped_class_value; i++) { ebitmap_init(dest->class_perms_map + i); } dest->class_perms_len = largest_mapped_class_value; for (i = 0; i < src->class_perms_len; i++) { ebitmap_t *srcmap = src->class_perms_map + i; ebitmap_t *destmap = dest->class_perms_map + module->map[SYM_CLASSES][i] - 1; ebitmap_for_each_bit(srcmap, node, j) { if (ebitmap_node_get_bit(node, j) && ebitmap_set_bit(destmap, module->perm_map[i][j] - 1, 1)) { goto cleanup; } } } return 0; cleanup: ERR(state->handle, "Out of memory!"); return -1; } static int copy_avrule_decl(link_state_t * state, policy_module_t * module, avrule_decl_t * src_decl, avrule_decl_t * dest_decl) { int ret; /* copy all of the RBAC and TE rules */ if (copy_avrule_list (src_decl->avrules, &dest_decl->avrules, module, state) == -1 || copy_role_trans_list(src_decl->role_tr_rules, &dest_decl->role_tr_rules, module, state) == -1 || copy_role_allow_list(src_decl->role_allow_rules, &dest_decl->role_allow_rules, module, state) == -1 || copy_cond_list(src_decl->cond_list, &dest_decl->cond_list, module, state) == -1) { return -1; } if (copy_filename_trans_list(src_decl->filename_trans_rules, &dest_decl->filename_trans_rules, module, state)) return -1; if (copy_range_trans_list(src_decl->range_tr_rules, &dest_decl->range_tr_rules, module, state)) return -1; /* finally copy any identifiers local to this declaration */ ret = copy_identifiers(state, src_decl->symtab, dest_decl); if (ret < 0) { return ret; } /* then copy required and declared scope indices here */ if (copy_scope_index(&src_decl->required, &dest_decl->required, module, state) == -1 || copy_scope_index(&src_decl->declared, &dest_decl->declared, module, state) == -1) { return -1; } return 0; } static int copy_avrule_block(link_state_t * state, policy_module_t * module, avrule_block_t * block) { avrule_block_t *new_block = avrule_block_create(); avrule_decl_t *decl, *last_decl = NULL; int ret; if (new_block == NULL) { ERR(state->handle, "Out of memory!"); ret = -1; goto cleanup; } new_block->flags = block->flags; for (decl = block->branch_list; decl != NULL; decl = decl->next) { avrule_decl_t *new_decl = avrule_decl_create(state->next_decl_id); if (new_decl == NULL) { ERR(state->handle, "Out of memory!"); ret = -1; goto cleanup; } if (module->policy->name != NULL) { new_decl->module_name = strdup(module->policy->name); if (new_decl->module_name == NULL) { ERR(state->handle, "Out of memory\n"); avrule_decl_destroy(new_decl); ret = -1; goto cleanup; } } if (last_decl == NULL) { new_block->branch_list = new_decl; } else { last_decl->next = new_decl; } last_decl = new_decl; state->base->decl_val_to_struct[state->next_decl_id - 1] = new_decl; state->decl_to_mod[state->next_decl_id] = module->policy; module->avdecl_map[decl->decl_id] = new_decl->decl_id; ret = copy_avrule_decl(state, module, decl, new_decl); if (ret) { avrule_decl_destroy(new_decl); goto cleanup; } state->next_decl_id++; } state->last_avrule_block->next = new_block; state->last_avrule_block = new_block; return 0; cleanup: avrule_block_list_destroy(new_block); return ret; } static int scope_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) { unsigned int i; int ret; char *id = key, *new_id = NULL; scope_datum_t *scope, *base_scope; link_state_t *state = (link_state_t *) data; uint32_t symbol_num = state->symbol_num; uint32_t *avdecl_map = state->cur->avdecl_map; scope = (scope_datum_t *) datum; /* check if the base already has a scope entry */ base_scope = hashtab_search(state->base->scope[symbol_num].table, id); if (base_scope == NULL) { scope_datum_t *new_scope; if ((new_id = strdup(id)) == NULL) { goto cleanup; } if ((new_scope = (scope_datum_t *) calloc(1, sizeof(*new_scope))) == NULL) { free(new_id); goto cleanup; } ret = hashtab_insert(state->base->scope[symbol_num].table, (hashtab_key_t) new_id, (hashtab_datum_t) new_scope); if (ret) { free(new_id); free(new_scope); goto cleanup; } new_scope->scope = SCOPE_REQ; /* this is reset further down */ base_scope = new_scope; } if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_DECL) { /* this module declared symbol, so overwrite the old * list with the new decl ids */ base_scope->scope = SCOPE_DECL; free(base_scope->decl_ids); base_scope->decl_ids = NULL; base_scope->decl_ids_len = 0; for (i = 0; i < scope->decl_ids_len; i++) { if (add_i_to_a(avdecl_map[scope->decl_ids[i]], &base_scope->decl_ids_len, &base_scope->decl_ids) == -1) { goto cleanup; } } } else if (base_scope->scope == SCOPE_DECL && scope->scope == SCOPE_REQ) { /* this module depended on a symbol that now exists, * so don't do anything */ } else if (base_scope->scope == SCOPE_REQ && scope->scope == SCOPE_REQ) { /* symbol is still required, so add to the list */ for (i = 0; i < scope->decl_ids_len; i++) { if (add_i_to_a(avdecl_map[scope->decl_ids[i]], &base_scope->decl_ids_len, &base_scope->decl_ids) == -1) { goto cleanup; } } } else { /* this module declared a symbol, and it was already * declared. only roles and users may be multiply * declared; for all others this is an error. */ if (symbol_num != SYM_ROLES && symbol_num != SYM_USERS) { ERR(state->handle, "%s: Duplicate declaration in module: %s %s", state->cur_mod_name, symtab_names[state->symbol_num], id); return -1; } for (i = 0; i < scope->decl_ids_len; i++) { if (add_i_to_a(avdecl_map[scope->decl_ids[i]], &base_scope->decl_ids_len, &base_scope->decl_ids) == -1) { goto cleanup; } } } return 0; cleanup: ERR(state->handle, "Out of memory!"); return -1; } /* Copy a module over to a base, remapping all values within. After * all identifiers and rules are done, copy the scoping information. * This is when it checks for duplicate declarations. */ static int copy_module(link_state_t * state, policy_module_t * module) { int i, ret; avrule_block_t *cur; state->cur = module; state->cur_mod_name = module->policy->name; /* first copy all of the identifiers */ ret = copy_identifiers(state, module->policy->symtab, NULL); if (ret) { return ret; } /* next copy all of the avrule blocks */ for (cur = module->policy->global; cur != NULL; cur = cur->next) { ret = copy_avrule_block(state, module, cur); if (ret) { return ret; } } /* then copy the scoping tables */ for (i = 0; i < SYM_NUM; i++) { state->symbol_num = i; if (hashtab_map (module->policy->scope[i].table, scope_copy_callback, state)) { return -1; } } return 0; } /***** functions that check requirements and enable blocks in a module ******/ /* borrowed from checkpolicy.c */ struct find_perm_arg { unsigned int valuep; hashtab_key_t key; }; static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *varg) { struct find_perm_arg *arg = varg; perm_datum_t *perdatum = (perm_datum_t *) datum; if (arg->valuep == perdatum->s.value) { arg->key = key; return 1; } return 0; } /* Check if the requirements are met for a single declaration. If all * are met return 1. For the first requirement found to be missing, * if 'missing_sym_num' and 'missing_value' are both not NULL then * write to them the symbol number and value for the missing * declaration. Then return 0 to indicate a missing declaration. * Note that if a declaration had no requirement at all (e.g., an ELSE * block) this returns 1. */ static int is_decl_requires_met(link_state_t * state, avrule_decl_t * decl, struct missing_requirement *req) { /* (This algorithm is very unoptimized. It performs many * redundant checks. A very obvious improvement is to cache * which symbols have been verified, so that they do not need * to be re-checked.) */ unsigned int i, j; ebitmap_t *bitmap; char *id, *perm_id; policydb_t *pol = state->base; ebitmap_node_t *node; /* check that all symbols have been satisfied */ for (i = 0; i < SYM_NUM; i++) { if (i == SYM_CLASSES) { /* classes will be checked during permissions * checking phase below */ continue; } bitmap = &decl->required.scope[i]; ebitmap_for_each_bit(bitmap, node, j) { if (!ebitmap_node_get_bit(node, j)) { continue; } /* check base's scope table */ id = pol->sym_val_to_name[i][j]; if (!is_id_enabled(id, state->base, i)) { /* this symbol was not found */ if (req != NULL) { req->symbol_type = i; req->symbol_value = j + 1; } return 0; } } } /* check that all classes and permissions have been satisfied */ for (i = 0; i < decl->required.class_perms_len; i++) { bitmap = decl->required.class_perms_map + i; ebitmap_for_each_bit(bitmap, node, j) { struct find_perm_arg fparg; class_datum_t *cladatum; uint32_t perm_value = j + 1; int rc; scope_datum_t *scope; if (!ebitmap_node_get_bit(node, j)) { continue; } id = pol->p_class_val_to_name[i]; cladatum = pol->class_val_to_struct[i]; scope = hashtab_search(state->base->p_classes_scope.table, id); if (scope == NULL) { ERR(state->handle, "Could not find scope information for class %s", id); return -1; } fparg.valuep = perm_value; fparg.key = NULL; (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg); if (fparg.key == NULL && cladatum->comdatum != NULL) { rc = hashtab_map(cladatum->comdatum->permissions.table, find_perm, &fparg); assert(rc == 1); } perm_id = fparg.key; assert(perm_id != NULL); if (!is_perm_enabled(id, perm_id, state->base)) { if (req != NULL) { req->symbol_type = SYM_CLASSES; req->symbol_value = i + 1; req->perm_value = perm_value; } return 0; } } } /* all requirements have been met */ return 1; } static int debug_requirements(link_state_t * state, policydb_t * p) { int ret; avrule_block_t *cur; missing_requirement_t req; memset(&req, 0, sizeof(req)); for (cur = p->global; cur != NULL; cur = cur->next) { if (cur->enabled != NULL) continue; ret = is_decl_requires_met(state, cur->branch_list, &req); if (ret < 0) { return ret; } else if (ret == 0) { char *mod_name = cur->branch_list->module_name ? cur->branch_list->module_name : "BASE"; if (req.symbol_type == SYM_CLASSES) { struct find_perm_arg fparg; class_datum_t *cladatum; cladatum = p->class_val_to_struct[req.symbol_value - 1]; fparg.valuep = req.perm_value; fparg.key = NULL; (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg); if (cur->flags & AVRULE_OPTIONAL) { ERR(state->handle, "%s[%d]'s optional requirements were not met: class %s, permission %s", mod_name, cur->branch_list->decl_id, p->p_class_val_to_name[req.symbol_value - 1], fparg.key); } else { ERR(state->handle, "%s[%d]'s global requirements were not met: class %s, permission %s", mod_name, cur->branch_list->decl_id, p->p_class_val_to_name[req.symbol_value - 1], fparg.key); } } else { if (cur->flags & AVRULE_OPTIONAL) { ERR(state->handle, "%s[%d]'s optional requirements were not met: %s %s", mod_name, cur->branch_list->decl_id, symtab_names[req.symbol_type], p->sym_val_to_name[req. symbol_type][req. symbol_value - 1]); } else { ERR(state->handle, "%s[%d]'s global requirements were not met: %s %s", mod_name, cur->branch_list->decl_id, symtab_names[req.symbol_type], p->sym_val_to_name[req. symbol_type][req. symbol_value - 1]); } } } } return 0; } static void print_missing_requirements(link_state_t * state, avrule_block_t * cur, missing_requirement_t * req) { policydb_t *p = state->base; char *mod_name = cur->branch_list->module_name ? cur->branch_list->module_name : "BASE"; if (req->symbol_type == SYM_CLASSES) { struct find_perm_arg fparg; class_datum_t *cladatum; cladatum = p->class_val_to_struct[req->symbol_value - 1]; fparg.valuep = req->perm_value; fparg.key = NULL; (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg); ERR(state->handle, "%s's global requirements were not met: class %s, permission %s", mod_name, p->p_class_val_to_name[req->symbol_value - 1], fparg.key); } else { ERR(state->handle, "%s's global requirements were not met: %s %s", mod_name, symtab_names[req->symbol_type], p->sym_val_to_name[req->symbol_type][req->symbol_value - 1]); } } /* Enable all of the avrule_decl blocks for the policy. This simple * algorithm is the following: * * 1) Enable all of the non-else avrule_decls for all blocks. * 2) Iterate through the non-else decls looking for decls whose requirements * are not met. * 2a) If the decl is non-optional, return immediately with an error. * 2b) If the decl is optional, disable the block and mark changed = 1 * 3) If changed == 1 goto 2. * 4) Iterate through all blocks looking for those that have no enabled * decl. If the block has an else decl, enable. * * This will correctly handle all dependencies, including mutual and * cicular. The only downside is that it is slow. */ static int enable_avrules(link_state_t * state, policydb_t * pol) { int changed = 1; avrule_block_t *block; avrule_decl_t *decl; missing_requirement_t req; int ret = 0, rc; if (state->verbose) { INFO(state->handle, "Determining which avrules to enable."); } /* 1) enable all of the non-else blocks */ for (block = pol->global; block != NULL; block = block->next) { block->enabled = block->branch_list; block->enabled->enabled = 1; for (decl = block->branch_list->next; decl != NULL; decl = decl->next) decl->enabled = 0; } /* 2) Iterate */ while (changed) { changed = 0; for (block = pol->global; block != NULL; block = block->next) { if (block->enabled == NULL) { continue; } decl = block->branch_list; if (state->verbose) { char *mod_name = decl->module_name ? decl->module_name : "BASE"; INFO(state->handle, "check module %s decl %d\n", mod_name, decl->decl_id); } rc = is_decl_requires_met(state, decl, &req); if (rc < 0) { ret = SEPOL_ERR; goto out; } else if (rc == 0) { decl->enabled = 0; block->enabled = NULL; changed = 1; if (!(block->flags & AVRULE_OPTIONAL)) { print_missing_requirements(state, block, &req); ret = SEPOL_EREQ; goto out; } } } } /* 4) else handling * * Iterate through all of the blocks skipping the first (which is the * global block, is required to be present, and cannot have an else). * If the block is disabled and has an else decl, enable that. * * This code assumes that the second block in the branch list is the else * block. This is currently supported by the compiler. */ for (block = pol->global->next; block != NULL; block = block->next) { if (block->enabled == NULL) { if (block->branch_list->next != NULL) { block->enabled = block->branch_list->next; block->branch_list->next->enabled = 1; } } } out: if (state->verbose) debug_requirements(state, pol); return ret; } /*********** the main linking functions ***********/ /* Given a module's policy, normalize all conditional expressions * within. Return 0 on success, -1 on error. */ static int cond_normalize(policydb_t * p) { avrule_block_t *block; for (block = p->global; block != NULL; block = block->next) { avrule_decl_t *decl; for (decl = block->branch_list; decl != NULL; decl = decl->next) { cond_list_t *cond = decl->cond_list; while (cond) { if (cond_normalize_expr(p, cond) < 0) return -1; cond = cond->next; } } } return 0; } /* Allocate space for the various remapping arrays. */ static int prepare_module(link_state_t * state, policy_module_t * module) { int i; uint32_t items, num_decls = 0; avrule_block_t *cur; /* allocate the maps */ for (i = 0; i < SYM_NUM; i++) { items = module->policy->symtab[i].nprim; if ((module->map[i] = (uint32_t *) calloc(items, sizeof(*module->map[i]))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } } /* allocate the permissions remap here */ items = module->policy->p_classes.nprim; if ((module->perm_map_len = calloc(items, sizeof(*module->perm_map_len))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } if ((module->perm_map = calloc(items, sizeof(*module->perm_map))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } /* allocate a map for avrule_decls */ for (cur = module->policy->global; cur != NULL; cur = cur->next) { avrule_decl_t *decl; for (decl = cur->branch_list; decl != NULL; decl = decl->next) { if (decl->decl_id > num_decls) { num_decls = decl->decl_id; } } } num_decls++; if ((module->avdecl_map = calloc(num_decls, sizeof(uint32_t))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } module->num_decls = num_decls; /* normalize conditionals within */ if (cond_normalize(module->policy) < 0) { ERR(state->handle, "Error while normalizing conditionals within the module %s.", module->policy->name); return -1; } return 0; } static int prepare_base(link_state_t * state, uint32_t num_mod_decls) { avrule_block_t *cur = state->base->global; assert(cur != NULL); state->next_decl_id = 0; /* iterate through all of the declarations in the base, to determine what the next decl_id should be */ while (cur != NULL) { avrule_decl_t *decl; for (decl = cur->branch_list; decl != NULL; decl = decl->next) { if (decl->decl_id > state->next_decl_id) { state->next_decl_id = decl->decl_id; } } state->last_avrule_block = cur; cur = cur->next; } state->last_base_avrule_block = state->last_avrule_block; state->next_decl_id++; /* allocate the table mapping from base's decl_id to its * avrule_decls and set the initial mappings */ free(state->base->decl_val_to_struct); if ((state->base->decl_val_to_struct = calloc(state->next_decl_id + num_mod_decls, sizeof(*(state->base->decl_val_to_struct)))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } /* This allocates the decl block to module mapping used for error reporting */ if ((state->decl_to_mod = calloc(state->next_decl_id + num_mod_decls, sizeof(*(state->decl_to_mod)))) == NULL) { ERR(state->handle, "Out of memory!"); return -1; } cur = state->base->global; while (cur != NULL) { avrule_decl_t *decl = cur->branch_list; while (decl != NULL) { state->base->decl_val_to_struct[decl->decl_id - 1] = decl; state->decl_to_mod[decl->decl_id] = state->base; decl = decl->next; } cur = cur->next; } /* normalize conditionals within */ if (cond_normalize(state->base) < 0) { ERR(state->handle, "Error while normalizing conditionals within the base module."); return -1; } return 0; } static int expand_role_attributes(hashtab_key_t key, hashtab_datum_t datum, void * data) { char *id; role_datum_t *role, *sub_attr; link_state_t *state; unsigned int i; ebitmap_node_t *rnode; id = key; role = (role_datum_t *)datum; state = (link_state_t *)data; if (strcmp(id, OBJECT_R) == 0){ /* object_r is never a role attribute by far */ return 0; } if (role->flavor != ROLE_ATTRIB) return 0; if (state->verbose) INFO(state->handle, "expanding role attribute %s", id); restart: ebitmap_for_each_bit(&role->roles, rnode, i) { if (ebitmap_node_get_bit(rnode, i)) { sub_attr = state->base->role_val_to_struct[i]; if (sub_attr->flavor != ROLE_ATTRIB) continue; /* remove the sub role attribute from the parent * role attribute's roles ebitmap */ if (ebitmap_set_bit(&role->roles, i, 0)) return -1; /* loop dependency of role attributes */ if (sub_attr->s.value == role->s.value) continue; /* now go on to expand a sub role attribute * by escalating its roles ebitmap */ if (ebitmap_union(&role->roles, &sub_attr->roles)) { ERR(state->handle, "Out of memory!"); return -1; } /* sub_attr->roles may contain other role attributes, * re-scan the parent role attribute's roles ebitmap */ goto restart; } } return 0; } /* For any role attribute in a declaration's local symtab[SYM_ROLES] table, * copy its roles ebitmap into its duplicate's in the base->p_roles.table. */ static int populate_decl_roleattributes(hashtab_key_t key, hashtab_datum_t datum, void *data) { char *id = key; role_datum_t *decl_role, *base_role; link_state_t *state = (link_state_t *)data; decl_role = (role_datum_t *)datum; if (strcmp(id, OBJECT_R) == 0) { /* object_r is never a role attribute by far */ return 0; } if (decl_role->flavor != ROLE_ATTRIB) return 0; base_role = (role_datum_t *)hashtab_search(state->base->p_roles.table, id); assert(base_role != NULL && base_role->flavor == ROLE_ATTRIB); if (ebitmap_union(&base_role->roles, &decl_role->roles)) { ERR(state->handle, "Out of memory!"); return -1; } return 0; } static int populate_roleattributes(link_state_t *state, policydb_t *pol) { avrule_block_t *block; avrule_decl_t *decl; if (state->verbose) INFO(state->handle, "Populating role-attribute relationship " "from enabled declarations' local symtab."); /* Iterate through all of the blocks skipping the first(which is the * global block, is required to be present and can't have an else). * If the block is disabled or not having an enabled decl, skip it. */ for (block = pol->global->next; block != NULL; block = block->next) { decl = block->enabled; if (decl == NULL || decl->enabled == 0) continue; if (hashtab_map(decl->symtab[SYM_ROLES].table, populate_decl_roleattributes, state)) return -1; } return 0; } /* Link a set of modules into a base module. This process is somewhat * similar to an actual compiler: it requires a set of order dependent * steps. The base and every module must have been indexed prior to * calling this function. */ int link_modules(sepol_handle_t * handle, policydb_t * b, policydb_t ** mods, int len, int verbose) { int i, ret, retval = -1; policy_module_t **modules = NULL; link_state_t state; uint32_t num_mod_decls = 0; memset(&state, 0, sizeof(state)); state.base = b; state.verbose = verbose; state.handle = handle; if (b->policy_type != POLICY_BASE) { ERR(state.handle, "Target of link was not a base policy."); return -1; } /* first allocate some space to hold the maps from module * symbol's value to the destination symbol value; then do * other preparation work */ if ((modules = (policy_module_t **) calloc(len, sizeof(*modules))) == NULL) { ERR(state.handle, "Out of memory!"); return -1; } for (i = 0; i < len; i++) { if (mods[i]->policy_type != POLICY_MOD) { ERR(state.handle, "Tried to link in a policy that was not a module."); goto cleanup; } if (mods[i]->mls != b->mls) { if (b->mls) ERR(state.handle, "Tried to link in a non-MLS module with an MLS base."); else ERR(state.handle, "Tried to link in an MLS module with a non-MLS base."); goto cleanup; } if ((modules[i] = (policy_module_t *) calloc(1, sizeof(policy_module_t))) == NULL) { ERR(state.handle, "Out of memory!"); goto cleanup; } modules[i]->policy = mods[i]; if (prepare_module(&state, modules[i]) == -1) { goto cleanup; } num_mod_decls += modules[i]->num_decls; } if (prepare_base(&state, num_mod_decls) == -1) { goto cleanup; } /* copy all types, declared and required */ for (i = 0; i < len; i++) { state.cur = modules[i]; state.cur_mod_name = modules[i]->policy->name; ret = hashtab_map(modules[i]->policy->p_types.table, type_copy_callback, &state); if (ret) { retval = ret; goto cleanup; } } /* then copy everything else, including aliases, and fixup attributes */ for (i = 0; i < len; i++) { state.cur = modules[i]; state.cur_mod_name = modules[i]->policy->name; ret = copy_identifiers(&state, modules[i]->policy->symtab, NULL); if (ret) { retval = ret; goto cleanup; } } if (policydb_index_others(state.handle, state.base, 0)) { ERR(state.handle, "Error while indexing others"); goto cleanup; } /* copy and remap the module's data over to base */ for (i = 0; i < len; i++) { state.cur = modules[i]; ret = copy_module(&state, modules[i]); if (ret) { retval = ret; goto cleanup; } } /* re-index base, for symbols were added to symbol tables */ if (policydb_index_classes(state.base)) { ERR(state.handle, "Error while indexing classes"); goto cleanup; } if (policydb_index_others(state.handle, state.base, 0)) { ERR(state.handle, "Error while indexing others"); goto cleanup; } if (enable_avrules(&state, state.base)) { retval = SEPOL_EREQ; goto cleanup; } /* Now that all role attribute's roles ebitmap have been settled, * escalate sub role attribute's roles ebitmap into that of parent. * * First, since some role-attribute relationships could be recorded * in some decl's local symtab(see get_local_role()), we need to * populate them up to the base.p_roles table. */ if (populate_roleattributes(&state, state.base)) { retval = SEPOL_EREQ; goto cleanup; } /* Now do the escalation. */ if (hashtab_map(state.base->p_roles.table, expand_role_attributes, &state)) goto cleanup; retval = 0; cleanup: for (i = 0; modules != NULL && i < len; i++) { policy_module_destroy(modules[i]); } free(modules); free(state.decl_to_mod); return retval; } libsepol-2.2/src/mls.c000066400000000000000000000434471223423440700147310ustar00rootroot00000000000000/* Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * * 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 */ /* FLASK */ /* * Implementation of the multi-level security (MLS) policy. */ #include #include #include #include #include #include "handle.h" #include "debug.h" #include "private.h" #include "mls.h" int mls_to_string(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * mls, char **str) { char *ptr = NULL, *ptr2 = NULL; /* Temporary buffer - length + NULL terminator */ int len = mls_compute_context_len(policydb, mls) + 1; ptr = (char *)malloc(len); if (ptr == NULL) goto omem; /* Final string w/ ':' cut off */ ptr2 = (char *)malloc(len - 1); if (ptr2 == NULL) goto omem; mls_sid_to_context(policydb, mls, &ptr); ptr -= len - 1; strcpy(ptr2, ptr + 1); free(ptr); *str = ptr2; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not convert mls context to string"); free(ptr); free(ptr2); return STATUS_ERR; } int mls_from_string(sepol_handle_t * handle, const policydb_t * policydb, const char *str, context_struct_t * mls) { char *tmp = strdup(str); char *tmp_cp = tmp; if (!tmp) goto omem; if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) { ERR(handle, "invalid MLS context %s", str); free(tmp); goto err; } free(tmp); return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not construct mls context structure"); return STATUS_ERR; } /* * Return the length in bytes for the MLS fields of the * security context string representation of `context'. */ int mls_compute_context_len(const policydb_t * policydb, const context_struct_t * context) { unsigned int i, l, len, range; ebitmap_node_t *cnode; if (!policydb->mls) return 0; len = 1; /* for the beginning ":" */ for (l = 0; l < 2; l++) { range = 0; len += strlen(policydb-> p_sens_val_to_name[context->range.level[l].sens - 1]); ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { if (range) { range++; continue; } len += strlen(policydb->p_cat_val_to_name[i]) + 1; range++; } else { if (range > 1) len += strlen(policydb-> p_cat_val_to_name[i - 1]) + 1; range = 0; } } /* Handle case where last category is the end of range */ if (range > 1) len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1; if (l == 0) { if (mls_level_eq(&context->range.level[0], &context->range.level[1])) break; else len++; } } return len; } /* * Write the security context string representation of * the MLS fields of `context' into the string `*scontext'. * Update `*scontext' to point to the end of the MLS fields. */ void mls_sid_to_context(const policydb_t * policydb, const context_struct_t * context, char **scontext) { char *scontextp; unsigned int i, l, range, wrote_sep; ebitmap_node_t *cnode; if (!policydb->mls) return; scontextp = *scontext; *scontextp = ':'; scontextp++; for (l = 0; l < 2; l++) { range = 0; wrote_sep = 0; strcpy(scontextp, policydb->p_sens_val_to_name[context->range.level[l]. sens - 1]); scontextp += strlen(policydb-> p_sens_val_to_name[context->range.level[l].sens - 1]); /* categories */ ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { if (range) { range++; continue; } if (!wrote_sep) { *scontextp++ = ':'; wrote_sep = 1; } else *scontextp++ = ','; strcpy(scontextp, policydb->p_cat_val_to_name[i]); scontextp += strlen(policydb->p_cat_val_to_name[i]); range++; } else { if (range > 1) { if (range > 2) *scontextp++ = '.'; else *scontextp++ = ','; strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]); scontextp += strlen(policydb-> p_cat_val_to_name[i - 1]); } range = 0; } } /* Handle case where last category is the end of range */ if (range > 1) { if (range > 2) *scontextp++ = '.'; else *scontextp++ = ','; strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]); scontextp += strlen(policydb->p_cat_val_to_name[i - 1]); } if (l == 0) { if (mls_level_eq(&context->range.level[0], &context->range.level[1])) break; else { *scontextp = '-'; scontextp++; } } } *scontext = scontextp; return; } /* * Return 1 if the MLS fields in the security context * structure `c' are valid. Return 0 otherwise. */ int mls_context_isvalid(const policydb_t * p, const context_struct_t * c) { level_datum_t *levdatum; user_datum_t *usrdatum; unsigned int i, l; ebitmap_node_t *cnode; if (!p->mls) return 1; /* * MLS range validity checks: high must dominate low, low level must * be valid (category set <-> sensitivity check), and high level must * be valid (category set <-> sensitivity check) */ if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) /* High does not dominate low. */ return 0; for (l = 0; l < 2; l++) { if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim) return 0; levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, p-> p_sens_val_to_name [c->range.level[l]. sens - 1]); if (!levdatum) return 0; ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { if (i > p->p_cats.nprim) return 0; if (!ebitmap_get_bit(&levdatum->level->cat, i)) /* * Category may not be associated with * sensitivity in low level. */ return 0; } } } if (c->role == OBJECT_R_VAL) return 1; /* * User must be authorized for the MLS range. */ if (!c->user || c->user > p->p_users.nprim) return 0; usrdatum = p->user_val_to_struct[c->user - 1]; if (!mls_range_contains(usrdatum->exp_range, c->range)) return 0; /* user may not be associated with range */ return 1; } /* * Set the MLS fields in the security context structure * `context' based on the string representation in * the string `*scontext'. Update `*scontext' to * point to the end of the string representation of * the MLS fields. * * This function modifies the string in place, inserting * NULL characters to terminate the MLS fields. */ int mls_context_to_sid(const policydb_t * policydb, char oldc, char **scontext, context_struct_t * context) { char delim; char *scontextp, *p, *rngptr; level_datum_t *levdatum; cat_datum_t *catdatum, *rngdatum; unsigned int l; if (!policydb->mls) return 0; /* No MLS component to the security context */ if (!oldc) goto err; /* Extract low sensitivity. */ scontextp = p = *scontext; while (*p && *p != ':' && *p != '-') p++; delim = *p; if (delim != 0) *p++ = 0; for (l = 0; l < 2; l++) { levdatum = (level_datum_t *) hashtab_search(policydb->p_levels.table, (hashtab_key_t) scontextp); if (!levdatum) goto err; context->range.level[l].sens = levdatum->level->sens; if (delim == ':') { /* Extract category set. */ while (1) { scontextp = p; while (*p && *p != ',' && *p != '-') p++; delim = *p; if (delim != 0) *p++ = 0; /* Separate into range if exists */ if ((rngptr = strchr(scontextp, '.')) != NULL) { /* Remove '.' */ *rngptr++ = 0; } catdatum = (cat_datum_t *) hashtab_search(policydb-> p_cats.table, (hashtab_key_t) scontextp); if (!catdatum) goto err; if (ebitmap_set_bit (&context->range.level[l].cat, catdatum->s.value - 1, 1)) goto err; /* If range, set all categories in range */ if (rngptr) { unsigned int i; rngdatum = (cat_datum_t *) hashtab_search(policydb->p_cats. table, (hashtab_key_t) rngptr); if (!rngdatum) goto err; if (catdatum->s.value >= rngdatum->s.value) goto err; for (i = catdatum->s.value; i < rngdatum->s.value; i++) { if (ebitmap_set_bit (&context->range.level[l]. cat, i, 1)) goto err; } } if (delim != ',') break; } } if (delim == '-') { /* Extract high sensitivity. */ scontextp = p; while (*p && *p != ':') p++; delim = *p; if (delim != 0) *p++ = 0; } else break; } /* High level is missing, copy low level */ if (l == 0) { if (mls_level_cpy(&context->range.level[1], &context->range.level[0]) < 0) goto err; } *scontext = ++p; return STATUS_SUCCESS; err: return STATUS_ERR; } /* * Copies the MLS range from `src' into `dst'. */ static inline int mls_copy_context(context_struct_t * dst, context_struct_t * src) { int l, rc = 0; /* Copy the MLS range from the source context */ for (l = 0; l < 2; l++) { dst->range.level[l].sens = src->range.level[l].sens; rc = ebitmap_cpy(&dst->range.level[l].cat, &src->range.level[l].cat); if (rc) break; } return rc; } /* * Copies the effective MLS range from `src' into `dst'. */ static inline int mls_scopy_context(context_struct_t * dst, context_struct_t * src) { int l, rc = 0; /* Copy the MLS range from the source context */ for (l = 0; l < 2; l++) { dst->range.level[l].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[l].cat, &src->range.level[0].cat); if (rc) break; } return rc; } /* * Copies the MLS range `range' into `context'. */ static inline int mls_range_set(context_struct_t * context, mls_range_t * range) { int l, rc = 0; /* Copy the MLS range into the context */ for (l = 0; l < 2; l++) { context->range.level[l].sens = range->level[l].sens; rc = ebitmap_cpy(&context->range.level[l].cat, &range->level[l].cat); if (rc) break; } return rc; } int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user, context_struct_t * usercon, int mls) { if (mls) { mls_level_t *fromcon_sen = &(fromcon->range.level[0]); mls_level_t *fromcon_clr = &(fromcon->range.level[1]); mls_level_t *user_low = &(user->exp_range.level[0]); mls_level_t *user_clr = &(user->exp_range.level[1]); mls_level_t *user_def = &(user->exp_dfltlevel); mls_level_t *usercon_sen = &(usercon->range.level[0]); mls_level_t *usercon_clr = &(usercon->range.level[1]); /* Honor the user's default level if we can */ if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { *usercon_sen = *user_def; } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { *usercon_sen = *fromcon_sen; } else if (mls_level_between(fromcon_clr, user_low, user_def)) { *usercon_sen = *user_low; } else return -EINVAL; /* Lower the clearance of available contexts if the clearance of "fromcon" is lower than that of the user's default clearance (but only if the "fromcon" clearance dominates the user's computed sensitivity level) */ if (mls_level_dom(user_clr, fromcon_clr)) { *usercon_clr = *fromcon_clr; } else if (mls_level_dom(fromcon_clr, user_clr)) { *usercon_clr = *user_clr; } else return -EINVAL; } return 0; } /* * Convert the MLS fields in the security context * structure `c' from the values specified in the * policy `oldp' to the values specified in the policy `newp'. */ int mls_convert_context(policydb_t * oldp, policydb_t * newp, context_struct_t * c) { level_datum_t *levdatum; cat_datum_t *catdatum; ebitmap_t bitmap; unsigned int l, i; ebitmap_node_t *cnode; if (!oldp->mls) return 0; for (l = 0; l < 2; l++) { levdatum = (level_datum_t *) hashtab_search(newp->p_levels.table, oldp-> p_sens_val_to_name[c-> range. level [l]. sens - 1]); if (!levdatum) return -EINVAL; c->range.level[l].sens = levdatum->level->sens; ebitmap_init(&bitmap); ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { int rc; catdatum = (cat_datum_t *) hashtab_search(newp->p_cats. table, oldp-> p_cat_val_to_name [i]); if (!catdatum) return -EINVAL; rc = ebitmap_set_bit(&bitmap, catdatum->s.value - 1, 1); if (rc) return rc; } } ebitmap_destroy(&c->range.level[l].cat); c->range.level[l].cat = bitmap; } return 0; } int mls_compute_sid(policydb_t * policydb, context_struct_t * scontext, context_struct_t * tcontext, sepol_security_class_t tclass, uint32_t specified, context_struct_t * newcontext) { range_trans_t *rtr; if (!policydb->mls) return 0; switch (specified) { case AVTAB_TRANSITION: /* Look for a range transition rule. */ for (rtr = policydb->range_tr; rtr; rtr = rtr->next) { if (rtr->source_type == scontext->type && rtr->target_type == tcontext->type && rtr->target_class == tclass) { /* Set the range from the rule */ return mls_range_set(newcontext, &rtr->target_range); } } /* Fallthrough */ case AVTAB_CHANGE: if (tclass == SECCLASS_PROCESS) /* Use the process MLS attributes. */ return mls_copy_context(newcontext, scontext); else /* Use the process effective MLS attributes. */ return mls_scopy_context(newcontext, scontext); case AVTAB_MEMBER: /* Only polyinstantiate the MLS attributes if the type is being polyinstantiated */ if (newcontext->type != tcontext->type) { /* Use the process effective MLS attributes. */ return mls_scopy_context(newcontext, scontext); } else { /* Use the related object MLS attributes. */ return mls_copy_context(newcontext, tcontext); } default: return -EINVAL; } return -EINVAL; } int sepol_mls_contains(sepol_handle_t * handle, sepol_policydb_t * policydb, const char *mls1, const char *mls2, int *response) { context_struct_t *ctx1 = NULL, *ctx2 = NULL; ctx1 = malloc(sizeof(context_struct_t)); ctx2 = malloc(sizeof(context_struct_t)); if (ctx1 == NULL || ctx2 == NULL) goto omem; context_init(ctx1); context_init(ctx2); if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0) goto err; if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0) goto err; *response = mls_range_contains(ctx1->range, ctx2->range); context_destroy(ctx1); context_destroy(ctx2); free(ctx1); free(ctx2); return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not check if mls context %s contains %s", mls1, mls2); context_destroy(ctx1); context_destroy(ctx2); free(ctx1); free(ctx2); return STATUS_ERR; } int sepol_mls_check(sepol_handle_t * handle, sepol_policydb_t * policydb, const char *mls) { int ret; context_struct_t *con = malloc(sizeof(context_struct_t)); if (!con) { ERR(handle, "out of memory, could not check if " "mls context %s is valid", mls); return STATUS_ERR; } context_init(con); ret = mls_from_string(handle, &policydb->p, mls, con); context_destroy(con); free(con); return ret; } void mls_semantic_cat_init(mls_semantic_cat_t * c) { memset(c, 0, sizeof(mls_semantic_cat_t)); } void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused))) { /* it's currently a simple struct - really nothing to destroy */ return; } void mls_semantic_level_init(mls_semantic_level_t * l) { memset(l, 0, sizeof(mls_semantic_level_t)); } void mls_semantic_level_destroy(mls_semantic_level_t * l) { mls_semantic_cat_t *cur, *next; if (l == NULL) return; next = l->cat; while (next) { cur = next; next = cur->next; mls_semantic_cat_destroy(cur); free(cur); } } int mls_semantic_level_cpy(mls_semantic_level_t * dst, mls_semantic_level_t * src) { mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL; mls_semantic_level_init(dst); dst->sens = src->sens; cat = src->cat; while (cat) { newcat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); if (!newcat) goto err; mls_semantic_cat_init(newcat); if (lnewcat) lnewcat->next = newcat; else dst->cat = newcat; newcat->low = cat->low; newcat->high = cat->high; lnewcat = newcat; cat = cat->next; } return 0; err: mls_semantic_level_destroy(dst); return -1; } void mls_semantic_range_init(mls_semantic_range_t * r) { mls_semantic_level_init(&r->level[0]); mls_semantic_level_init(&r->level[1]); } void mls_semantic_range_destroy(mls_semantic_range_t * r) { mls_semantic_level_destroy(&r->level[0]); mls_semantic_level_destroy(&r->level[1]); } int mls_semantic_range_cpy(mls_semantic_range_t * dst, mls_semantic_range_t * src) { if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0) return -1; if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) { mls_semantic_level_destroy(&dst->level[0]); return -1; } return 0; } libsepol-2.2/src/mls.h000066400000000000000000000045211223423440700147240ustar00rootroot00000000000000/* Author: Stephen Smalley, * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * * 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 */ #ifndef _SEPOL_MLS_INTERNAL_H_ #define _SEPOL_MLS_INTERNAL_H_ #include "policydb_internal.h" #include #include "handle.h" extern int mls_from_string(sepol_handle_t * handle, const policydb_t * policydb, const char *str, context_struct_t * mls); extern int mls_to_string(sepol_handle_t * handle, const policydb_t * policydb, const context_struct_t * mls, char **str); /* Deprecated */ extern int mls_compute_context_len(const policydb_t * policydb, const context_struct_t * context); /* Deprecated */ extern void mls_sid_to_context(const policydb_t * policydb, const context_struct_t * context, char **scontext); /* Deprecated */ extern int mls_context_to_sid(const policydb_t * policydb, char oldc, char **scontext, context_struct_t * context); extern int mls_context_isvalid(const policydb_t * p, const context_struct_t * c); extern int mls_convert_context(policydb_t * oldp, policydb_t * newp, context_struct_t * context); extern int mls_compute_sid(policydb_t * policydb, context_struct_t * scontext, context_struct_t * tcontext, sepol_security_class_t tclass, uint32_t specified, context_struct_t * newcontext); extern int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user, context_struct_t * usercon, int mls); #endif libsepol-2.2/src/module.c000066400000000000000000000573221223423440700154200ustar00rootroot00000000000000/* Author: Karl MacMillan * Jason Tang * Chris PeBenito * * Copyright (C) 2004-2005 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 "policydb_internal.h" #include "module_internal.h" #include #include #include #include "debug.h" #include "private.h" #include #include #include #define SEPOL_PACKAGE_SECTION_FC 0xf97cff90 #define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91 #define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92 #define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93 static int policy_file_seek(struct policy_file *fp, size_t offset) { switch (fp->type) { case PF_USE_STDIO: if (offset > LONG_MAX) { errno = EFAULT; return -1; } return fseek(fp->fp, (long)offset, SEEK_SET); case PF_USE_MEMORY: if (offset > fp->size) { errno = EFAULT; return -1; } fp->data -= fp->size - fp->len; fp->data += offset; fp->len = fp->size - offset; return 0; default: return 0; } } static int policy_file_length(struct policy_file *fp, size_t *out) { long prev_offset, end_offset; int rc; switch (fp->type) { case PF_USE_STDIO: prev_offset = ftell(fp->fp); if (prev_offset < 0) return prev_offset; rc = fseek(fp->fp, 0L, SEEK_END); if (rc < 0) return rc; end_offset = ftell(fp->fp); if (end_offset < 0) return end_offset; rc = fseek(fp->fp, prev_offset, SEEK_SET); if (rc < 0) return rc; *out = end_offset; break; case PF_USE_MEMORY: *out = fp->size; break;; default: *out = 0; break; } return 0; } static int module_package_init(sepol_module_package_t * p) { memset(p, 0, sizeof(sepol_module_package_t)); if (sepol_policydb_create(&p->policy)) return -1; p->version = 1; return 0; } static int set_char(char **field, char *data, size_t len) { if (*field) { free(*field); *field = NULL; } if (len) { *field = malloc(len); if (!*field) return -1; memcpy(*field, data, len); } return 0; } int sepol_module_package_create(sepol_module_package_t ** p) { int rc; *p = calloc(1, sizeof(sepol_module_package_t)); if (!(*p)) return -1; rc = module_package_init(*p); if (rc < 0) free(*p); return rc; } hidden_def(sepol_module_package_create) /* Deallocates all memory associated with a module package, including * the pointer itself. Does nothing if p is NULL. */ void sepol_module_package_free(sepol_module_package_t * p) { if (p == NULL) return; sepol_policydb_free(p->policy); free(p->file_contexts); free(p->seusers); free(p->user_extra); free(p->netfilter_contexts); free(p); } hidden_def(sepol_module_package_free) char *sepol_module_package_get_file_contexts(sepol_module_package_t * p) { return p->file_contexts; } size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p) { return p->file_contexts_len; } char *sepol_module_package_get_seusers(sepol_module_package_t * p) { return p->seusers; } size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p) { return p->seusers_len; } char *sepol_module_package_get_user_extra(sepol_module_package_t * p) { return p->user_extra; } size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p) { return p->user_extra_len; } char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p) { return p->netfilter_contexts; } size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t * p) { return p->netfilter_contexts_len; } int sepol_module_package_set_file_contexts(sepol_module_package_t * p, char *data, size_t len) { if (set_char(&p->file_contexts, data, len)) return -1; p->file_contexts_len = len; return 0; } int sepol_module_package_set_seusers(sepol_module_package_t * p, char *data, size_t len) { if (set_char(&p->seusers, data, len)) return -1; p->seusers_len = len; return 0; } int sepol_module_package_set_user_extra(sepol_module_package_t * p, char *data, size_t len) { if (set_char(&p->user_extra, data, len)) return -1; p->user_extra_len = len; return 0; } int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p, char *data, size_t len) { if (set_char(&p->netfilter_contexts, data, len)) return -1; p->netfilter_contexts_len = len; return 0; } sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p) { return p->policy; } /* Append each of the file contexts from each module to the base * policy's file context. 'base_context' will be reallocated to a * larger size (and thus it is an in/out reference * variable). 'base_fc_len' is the length of base's file context; it * too is a reference variable. Return 0 on success, -1 if out of * memory. */ static int link_file_contexts(sepol_module_package_t * base, sepol_module_package_t ** modules, int num_modules) { size_t fc_len; int i; char *s; fc_len = base->file_contexts_len; for (i = 0; i < num_modules; i++) { fc_len += modules[i]->file_contexts_len; } if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) { return -1; } base->file_contexts = s; for (i = 0; i < num_modules; i++) { memcpy(base->file_contexts + base->file_contexts_len, modules[i]->file_contexts, modules[i]->file_contexts_len); base->file_contexts_len += modules[i]->file_contexts_len; } return 0; } /* Append each of the netfilter contexts from each module to the base * policy's netfilter context. 'base_context' will be reallocated to a * larger size (and thus it is an in/out reference * variable). 'base_nc_len' is the length of base's netfilter contexts; it * too is a reference variable. Return 0 on success, -1 if out of * memory. */ static int link_netfilter_contexts(sepol_module_package_t * base, sepol_module_package_t ** modules, int num_modules) { size_t base_nc_len; int i; char *base_context; base_nc_len = base->netfilter_contexts_len; for (i = 0; i < num_modules; i++) { base_nc_len += modules[i]->netfilter_contexts_len; } if ((base_context = (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) { return -1; } base->netfilter_contexts = base_context; for (i = 0; i < num_modules; i++) { memcpy(base->netfilter_contexts + base->netfilter_contexts_len, modules[i]->netfilter_contexts, modules[i]->netfilter_contexts_len); base->netfilter_contexts_len += modules[i]->netfilter_contexts_len; } return 0; } /* Links the module packages into the base. Returns 0 on success, -1 * if a requirement was not met, or -2 for all other errors. */ int sepol_link_packages(sepol_handle_t * handle, sepol_module_package_t * base, sepol_module_package_t ** modules, int num_modules, int verbose) { policydb_t **mod_pols = NULL; int i, retval; if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) { ERR(handle, "Out of memory!"); return -2; } for (i = 0; i < num_modules; i++) { mod_pols[i] = &modules[i]->policy->p; } retval = link_modules(handle, &base->policy->p, mod_pols, num_modules, verbose); free(mod_pols); if (retval == -3) { return -1; } else if (retval < 0) { return -2; } if (link_file_contexts(base, modules, num_modules) == -1) { ERR(handle, "Out of memory!"); return -2; } if (link_netfilter_contexts(base, modules, num_modules) == -1) { ERR(handle, "Out of memory!"); return -2; } return 0; } /* buf must be large enough - no checks are performed */ #define _read_helper_bufsize BUFSIZ static int read_helper(char *buf, struct policy_file *file, uint32_t bytes) { uint32_t offset, nel, read_len; int rc; offset = 0; nel = bytes; while (nel) { if (nel < _read_helper_bufsize) read_len = nel; else read_len = _read_helper_bufsize; rc = next_entry(&buf[offset], file, read_len); if (rc < 0) return -1; offset += read_len; nel -= read_len; } return 0; } #define MAXSECTIONS 100 /* Get the section offsets from a package file, offsets will be malloc'd to * the appropriate size and the caller must free() them */ static int module_package_read_offsets(sepol_module_package_t * mod, struct policy_file *file, size_t ** offsets, uint32_t * sections) { uint32_t *buf = NULL, nsec; unsigned i; size_t *off = NULL; int rc; buf = malloc(sizeof(uint32_t)*3); if (!buf) { ERR(file->handle, "out of memory"); goto err; } rc = next_entry(buf, file, sizeof(uint32_t) * 3); if (rc < 0) { ERR(file->handle, "module package header truncated"); goto err; } if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) { ERR(file->handle, "wrong magic number for module package: expected %#08x, got %#08x", SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0])); goto err; } mod->version = le32_to_cpu(buf[1]); nsec = *sections = le32_to_cpu(buf[2]); if (nsec > MAXSECTIONS) { ERR(file->handle, "too many sections (%u) in module package", nsec); goto err; } off = (size_t *) malloc((nsec + 1) * sizeof(size_t)); if (!off) { ERR(file->handle, "out of memory"); goto err; } free(buf); buf = malloc(sizeof(uint32_t) * nsec); if (!buf) { ERR(file->handle, "out of memory"); goto err; } rc = next_entry(buf, file, sizeof(uint32_t) * nsec); if (rc < 0) { ERR(file->handle, "module package offset array truncated"); goto err; } for (i = 0; i < nsec; i++) { off[i] = le32_to_cpu(buf[i]); if (i && off[i] < off[i - 1]) { ERR(file->handle, "offsets are not increasing (at %u, " "offset %zu -> %zu", i, off[i - 1], off[i]); goto err; } } rc = policy_file_length(file, &off[nsec]); if (rc < 0) goto err; if (nsec && off[nsec] < off[nsec-1]) { ERR(file->handle, "offset greater than file size (at %u, " "offset %zu -> %zu", nsec, off[nsec - 1], off[nsec]); goto err; } *offsets = off; free(buf); return 0; err: free(buf); free(off); return -1; } /* Flags for which sections have been seen during parsing of module package. */ #define SEEN_MOD 1 #define SEEN_FC 2 #define SEEN_SEUSER 4 #define SEEN_USER_EXTRA 8 #define SEEN_NETFILTER 16 int sepol_module_package_read(sepol_module_package_t * mod, struct sepol_policy_file *spf, int verbose) { struct policy_file *file = &spf->pf; uint32_t buf[1], nsec; size_t *offsets, len; int rc; unsigned i, seen = 0; if (module_package_read_offsets(mod, file, &offsets, &nsec)) return -1; /* we know the section offsets, seek to them and read in the data */ for (i = 0; i < nsec; i++) { if (policy_file_seek(file, offsets[i])) { ERR(file->handle, "error seeking to offset %zu for " "module package section %u", offsets[i], i); goto cleanup; } len = offsets[i + 1] - offsets[i]; if (len < sizeof(uint32_t)) { ERR(file->handle, "module package section %u " "has too small length %zu", i, len); goto cleanup; } /* read the magic number, so that we know which function to call */ rc = next_entry(buf, file, sizeof(uint32_t)); if (rc < 0) { ERR(file->handle, "module package section %u truncated, lacks magic number", i); goto cleanup; } switch (le32_to_cpu(buf[0])) { case SEPOL_PACKAGE_SECTION_FC: if (seen & SEEN_FC) { ERR(file->handle, "found multiple file contexts sections in module package (at section %u)", i); goto cleanup; } mod->file_contexts_len = len - sizeof(uint32_t); mod->file_contexts = (char *)malloc(mod->file_contexts_len); if (!mod->file_contexts) { ERR(file->handle, "out of memory"); goto cleanup; } if (read_helper (mod->file_contexts, file, mod->file_contexts_len)) { ERR(file->handle, "invalid file contexts section at section %u", i); free(mod->file_contexts); mod->file_contexts = NULL; goto cleanup; } seen |= SEEN_FC; break; case SEPOL_PACKAGE_SECTION_SEUSER: if (seen & SEEN_SEUSER) { ERR(file->handle, "found multiple seuser sections in module package (at section %u)", i); goto cleanup; } mod->seusers_len = len - sizeof(uint32_t); mod->seusers = (char *)malloc(mod->seusers_len); if (!mod->seusers) { ERR(file->handle, "out of memory"); goto cleanup; } if (read_helper(mod->seusers, file, mod->seusers_len)) { ERR(file->handle, "invalid seuser section at section %u", i); free(mod->seusers); mod->seusers = NULL; goto cleanup; } seen |= SEEN_SEUSER; break; case SEPOL_PACKAGE_SECTION_USER_EXTRA: if (seen & SEEN_USER_EXTRA) { ERR(file->handle, "found multiple user_extra sections in module package (at section %u)", i); goto cleanup; } mod->user_extra_len = len - sizeof(uint32_t); mod->user_extra = (char *)malloc(mod->user_extra_len); if (!mod->user_extra) { ERR(file->handle, "out of memory"); goto cleanup; } if (read_helper (mod->user_extra, file, mod->user_extra_len)) { ERR(file->handle, "invalid user_extra section at section %u", i); free(mod->user_extra); mod->user_extra = NULL; goto cleanup; } seen |= SEEN_USER_EXTRA; break; case SEPOL_PACKAGE_SECTION_NETFILTER: if (seen & SEEN_NETFILTER) { ERR(file->handle, "found multiple netfilter contexts sections in module package (at section %u)", i); goto cleanup; } mod->netfilter_contexts_len = len - sizeof(uint32_t); mod->netfilter_contexts = (char *)malloc(mod->netfilter_contexts_len); if (!mod->netfilter_contexts) { ERR(file->handle, "out of memory"); goto cleanup; } if (read_helper (mod->netfilter_contexts, file, mod->netfilter_contexts_len)) { ERR(file->handle, "invalid netfilter contexts section at section %u", i); free(mod->netfilter_contexts); mod->netfilter_contexts = NULL; goto cleanup; } seen |= SEEN_NETFILTER; break; case POLICYDB_MOD_MAGIC: if (seen & SEEN_MOD) { ERR(file->handle, "found multiple module sections in module package (at section %u)", i); goto cleanup; } /* seek back to where the magic number was */ if (policy_file_seek(file, offsets[i])) goto cleanup; rc = policydb_read(&mod->policy->p, file, verbose); if (rc < 0) { ERR(file->handle, "invalid module in module package (at section %u)", i); goto cleanup; } seen |= SEEN_MOD; break; default: /* unknown section, ignore */ ERR(file->handle, "unknown magic number at section %u, offset: %zx, number: %ux ", i, offsets[i], le32_to_cpu(buf[0])); break; } } if ((seen & SEEN_MOD) == 0) { ERR(file->handle, "missing module in module package"); goto cleanup; } free(offsets); return 0; cleanup: free(offsets); return -1; } int sepol_module_package_info(struct sepol_policy_file *spf, int *type, char **name, char **version) { struct policy_file *file = &spf->pf; sepol_module_package_t *mod = NULL; uint32_t buf[5], len, nsec; size_t *offsets = NULL; unsigned i, seen = 0; char *id; int rc; if (sepol_module_package_create(&mod)) return -1; if (module_package_read_offsets(mod, file, &offsets, &nsec)) { goto cleanup; } for (i = 0; i < nsec; i++) { if (policy_file_seek(file, offsets[i])) { ERR(file->handle, "error seeking to offset " "%zu for module package section %u", offsets[i], i); goto cleanup; } len = offsets[i + 1] - offsets[i]; if (len < sizeof(uint32_t)) { ERR(file->handle, "module package section %u has too small length %u", i, len); goto cleanup; } /* read the magic number, so that we know which function to call */ rc = next_entry(buf, file, sizeof(uint32_t) * 2); if (rc < 0) { ERR(file->handle, "module package section %u truncated, lacks magic number", i); goto cleanup; } switch (le32_to_cpu(buf[0])) { case SEPOL_PACKAGE_SECTION_FC: /* skip file contexts */ if (seen & SEEN_FC) { ERR(file->handle, "found multiple file contexts sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_FC; break; case SEPOL_PACKAGE_SECTION_SEUSER: /* skip seuser */ if (seen & SEEN_SEUSER) { ERR(file->handle, "found seuser sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_SEUSER; break; case SEPOL_PACKAGE_SECTION_USER_EXTRA: /* skip user_extra */ if (seen & SEEN_USER_EXTRA) { ERR(file->handle, "found user_extra sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_USER_EXTRA; break; case SEPOL_PACKAGE_SECTION_NETFILTER: /* skip netfilter contexts */ if (seen & SEEN_NETFILTER) { ERR(file->handle, "found multiple netfilter contexts sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_NETFILTER; break; case POLICYDB_MOD_MAGIC: if (seen & SEEN_MOD) { ERR(file->handle, "found multiple module sections in module package (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_MOD_STRING)) { ERR(file->handle, "module string length is wrong (at section %u)", i); goto cleanup; } /* skip id */ id = malloc(len + 1); if (!id) { ERR(file->handle, "out of memory (at section %u)", i); goto cleanup; } rc = next_entry(id, file, len); free(id); if (rc < 0) { ERR(file->handle, "cannot get module string (at section %u)", i); goto cleanup; } rc = next_entry(buf, file, sizeof(uint32_t) * 5); if (rc < 0) { ERR(file->handle, "cannot get module header (at section %u)", i); goto cleanup; } *type = le32_to_cpu(buf[0]); /* if base - we're done */ if (*type == POLICY_BASE) { *name = NULL; *version = NULL; seen |= SEEN_MOD; break; } else if (*type != POLICY_MOD) { ERR(file->handle, "module has invalid type %d (at section %u)", *type, i); goto cleanup; } /* read the name and version */ rc = next_entry(buf, file, sizeof(uint32_t)); if (rc < 0) { ERR(file->handle, "cannot get module name len (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[0]); *name = malloc(len + 1); if (!*name) { ERR(file->handle, "out of memory"); goto cleanup; } rc = next_entry(*name, file, len); if (rc < 0) { ERR(file->handle, "cannot get module name string (at section %u)", i); goto cleanup; } (*name)[len] = '\0'; rc = next_entry(buf, file, sizeof(uint32_t)); if (rc < 0) { ERR(file->handle, "cannot get module version len (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[0]); *version = malloc(len + 1); if (!*version) { ERR(file->handle, "out of memory"); goto cleanup; } rc = next_entry(*version, file, len); if (rc < 0) { ERR(file->handle, "cannot get module version string (at section %u)", i); goto cleanup; } (*version)[len] = '\0'; seen |= SEEN_MOD; break; default: break; } } if ((seen & SEEN_MOD) == 0) { ERR(file->handle, "missing module in module package"); goto cleanup; } sepol_module_package_free(mod); free(offsets); return 0; cleanup: sepol_module_package_free(mod); free(offsets); return -1; } static int write_helper(char *data, size_t len, struct policy_file *file) { int idx = 0; size_t len2; while (len) { if (len > BUFSIZ) len2 = BUFSIZ; else len2 = len; if (put_entry(&data[idx], 1, len2, file) != len2) { return -1; } len -= len2; idx += len2; } return 0; } int sepol_module_package_write(sepol_module_package_t * p, struct sepol_policy_file *spf) { struct policy_file *file = &spf->pf; policy_file_t polfile; uint32_t buf[5], offsets[5], len, nsec = 0; int i; if (p->policy) { /* compute policy length */ policy_file_init(&polfile); polfile.type = PF_LEN; polfile.handle = file->handle; if (policydb_write(&p->policy->p, &polfile)) return -1; len = polfile.len; if (!polfile.len) return -1; nsec++; } else { /* We don't support writing a package without a module at this point */ return -1; } /* seusers and user_extra only supported in base at the moment */ if ((p->seusers || p->user_extra) && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) { ERR(file->handle, "seuser and user_extra sections only supported in base"); return -1; } if (p->file_contexts) nsec++; if (p->seusers) nsec++; if (p->user_extra) nsec++; if (p->netfilter_contexts) nsec++; buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC); buf[1] = cpu_to_le32(p->version); buf[2] = cpu_to_le32(nsec); if (put_entry(buf, sizeof(uint32_t), 3, file) != 3) return -1; /* calculate offsets */ offsets[0] = (nsec + 3) * sizeof(uint32_t); buf[0] = cpu_to_le32(offsets[0]); i = 1; if (p->file_contexts) { offsets[i] = offsets[i - 1] + len; buf[i] = cpu_to_le32(offsets[i]); /* add a uint32_t to compensate for the magic number */ len = p->file_contexts_len + sizeof(uint32_t); i++; } if (p->seusers) { offsets[i] = offsets[i - 1] + len; buf[i] = cpu_to_le32(offsets[i]); len = p->seusers_len + sizeof(uint32_t); i++; } if (p->user_extra) { offsets[i] = offsets[i - 1] + len; buf[i] = cpu_to_le32(offsets[i]); len = p->user_extra_len + sizeof(uint32_t); i++; } if (p->netfilter_contexts) { offsets[i] = offsets[i - 1] + len; buf[i] = cpu_to_le32(offsets[i]); len = p->netfilter_contexts_len + sizeof(uint32_t); i++; } if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec) return -1; /* write sections */ if (policydb_write(&p->policy->p, file)) return -1; if (p->file_contexts) { buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC); if (put_entry(buf, sizeof(uint32_t), 1, file) != 1) return -1; if (write_helper(p->file_contexts, p->file_contexts_len, file)) return -1; } if (p->seusers) { buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER); if (put_entry(buf, sizeof(uint32_t), 1, file) != 1) return -1; if (write_helper(p->seusers, p->seusers_len, file)) return -1; } if (p->user_extra) { buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA); if (put_entry(buf, sizeof(uint32_t), 1, file) != 1) return -1; if (write_helper(p->user_extra, p->user_extra_len, file)) return -1; } if (p->netfilter_contexts) { buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER); if (put_entry(buf, sizeof(uint32_t), 1, file) != 1) return -1; if (write_helper (p->netfilter_contexts, p->netfilter_contexts_len, file)) return -1; } return 0; } int sepol_link_modules(sepol_handle_t * handle, sepol_policydb_t * base, sepol_policydb_t ** modules, size_t len, int verbose) { return link_modules(handle, &base->p, (policydb_t **) modules, len, verbose); } int sepol_expand_module(sepol_handle_t * handle, sepol_policydb_t * base, sepol_policydb_t * out, int verbose, int check) { return expand_module(handle, &base->p, &out->p, verbose, check); } libsepol-2.2/src/module_internal.h000066400000000000000000000002021223423440700173020ustar00rootroot00000000000000#include #include "dso.h" hidden_proto(sepol_module_package_create) hidden_proto(sepol_module_package_free) libsepol-2.2/src/node_internal.h000066400000000000000000000015251223423440700167530ustar00rootroot00000000000000#ifndef _SEPOL_NODE_INTERNAL_H_ #define _SEPOL_NODE_INTERNAL_H_ #include #include #include "dso.h" hidden_proto(sepol_node_create) hidden_proto(sepol_node_key_free) hidden_proto(sepol_node_free) hidden_proto(sepol_node_get_con) hidden_proto(sepol_node_get_addr) hidden_proto(sepol_node_get_addr_bytes) hidden_proto(sepol_node_get_mask) hidden_proto(sepol_node_get_mask_bytes) hidden_proto(sepol_node_get_proto) hidden_proto(sepol_node_get_proto_str) hidden_proto(sepol_node_key_create) hidden_proto(sepol_node_key_unpack) hidden_proto(sepol_node_set_con) hidden_proto(sepol_node_set_addr) hidden_proto(sepol_node_set_addr_bytes) hidden_proto(sepol_node_set_mask) hidden_proto(sepol_node_set_mask_bytes) hidden_proto(sepol_node_set_proto) #endif libsepol-2.2/src/node_record.c000066400000000000000000000324571223423440700164200ustar00rootroot00000000000000#include #include #include #include #include #include #include "node_internal.h" #include "context_internal.h" #include "debug.h" struct sepol_node { /* Network address and mask */ char *addr; size_t addr_sz; char *mask; size_t mask_sz; /* Protocol */ int proto; /* Context */ sepol_context_t *con; }; struct sepol_node_key { /* Network address and mask */ char *addr; size_t addr_sz; char *mask; size_t mask_sz; /* Protocol */ int proto; }; /* Converts a string represtation (addr_str) * to a numeric representation (addr_bytes) */ static int node_parse_addr(sepol_handle_t * handle, const char *addr_str, int proto, char *addr_bytes) { switch (proto) { case SEPOL_PROTO_IP4: { struct in_addr in_addr; if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) { ERR(handle, "could not parse IPv4 address " "%s: %s", addr_str, strerror(errno)); return STATUS_ERR; } memcpy(addr_bytes, &in_addr.s_addr, 4); break; } case SEPOL_PROTO_IP6: { struct in6_addr in_addr; if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) { ERR(handle, "could not parse IPv6 address " "%s: %s", addr_str, strerror(errno)); return STATUS_ERR; } #ifdef DARWIN memcpy(addr_bytes, in_addr.s6_addr, 16); #else memcpy(addr_bytes, in_addr.s6_addr32, 16); #endif break; } default: ERR(handle, "unsupported protocol %u, could not " "parse address", proto); return STATUS_ERR; } return STATUS_SUCCESS; } /* Allocates a sufficiently large buffer (addr, addr_sz) * according the the protocol */ static int node_alloc_addr(sepol_handle_t * handle, int proto, char **addr, size_t * addr_sz) { char *tmp_addr = NULL; size_t tmp_addr_sz; switch (proto) { case SEPOL_PROTO_IP4: tmp_addr_sz = 4; tmp_addr = malloc(4); if (!tmp_addr) goto omem; break; case SEPOL_PROTO_IP6: tmp_addr_sz = 16; tmp_addr = malloc(16); if (!tmp_addr) goto omem; break; default: ERR(handle, "unsupported protocol %u", proto); goto err; } *addr = tmp_addr; *addr_sz = tmp_addr_sz; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: free(tmp_addr); ERR(handle, "could not allocate address of protocol %s", sepol_node_get_proto_str(proto)); return STATUS_ERR; } /* Converts a numeric representation (addr_bytes) * to a string representation (addr_str), according to * the protocol */ static int node_expand_addr(sepol_handle_t * handle, char *addr_bytes, int proto, char *addr_str) { switch (proto) { case SEPOL_PROTO_IP4: { struct in_addr addr; memset(&addr, 0, sizeof(struct in_addr)); memcpy(&addr.s_addr, addr_bytes, 4); if (inet_ntop(AF_INET, &addr, addr_str, INET_ADDRSTRLEN) == NULL) { ERR(handle, "could not expand IPv4 address to string: %s", strerror(errno)); return STATUS_ERR; } break; } case SEPOL_PROTO_IP6: { struct in6_addr addr; memset(&addr, 0, sizeof(struct in6_addr)); #ifdef DARWIN memcpy(&addr.s6_addr[0], addr_bytes, 16); #else memcpy(&addr.s6_addr32[0], addr_bytes, 16); #endif if (inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN) == NULL) { ERR(handle, "could not expand IPv6 address to string: %s", strerror(errno)); return STATUS_ERR; } break; } default: ERR(handle, "unsupported protocol %u, could not" " expand address to string", proto); return STATUS_ERR; } return STATUS_SUCCESS; } /* Allocates a sufficiently large address string (addr) * according to the protocol */ static int node_alloc_addr_string(sepol_handle_t * handle, int proto, char **addr) { char *tmp_addr = NULL; switch (proto) { case SEPOL_PROTO_IP4: tmp_addr = malloc(INET_ADDRSTRLEN); if (!tmp_addr) goto omem; break; case SEPOL_PROTO_IP6: tmp_addr = malloc(INET6_ADDRSTRLEN); if (!tmp_addr) goto omem; break; default: ERR(handle, "unsupported protocol %u", proto); goto err; } *addr = tmp_addr; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: free(tmp_addr); ERR(handle, "could not allocate string buffer for " "address of protocol %s", sepol_node_get_proto_str(proto)); return STATUS_ERR; } /* Key */ int sepol_node_key_create(sepol_handle_t * handle, const char *addr, const char *mask, int proto, sepol_node_key_t ** key_ptr) { sepol_node_key_t *tmp_key = (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t)); if (!tmp_key) goto omem; if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) < 0) goto err; if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0) goto err; if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) < 0) goto err; if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0) goto err; tmp_key->proto = proto; *key_ptr = tmp_key; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: sepol_node_key_free(tmp_key); ERR(handle, "could not create node key for (%s, %s, %s)", addr, mask, sepol_node_get_proto_str(proto)); return STATUS_ERR; } hidden_def(sepol_node_key_create) void sepol_node_key_unpack(const sepol_node_key_t * key, const char **addr, const char **mask, int *proto) { *addr = key->addr; *mask = key->mask; *proto = key->proto; } hidden_def(sepol_node_key_unpack) int sepol_node_key_extract(sepol_handle_t * handle, const sepol_node_t * node, sepol_node_key_t ** key_ptr) { sepol_node_key_t *tmp_key = (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t)); if (!tmp_key) goto omem; tmp_key->addr = malloc(node->addr_sz); tmp_key->mask = malloc(node->mask_sz); if (!tmp_key->addr || !tmp_key->mask) goto omem; memcpy(tmp_key->addr, node->addr, node->addr_sz); memcpy(tmp_key->mask, node->mask, node->mask_sz); tmp_key->addr_sz = node->addr_sz; tmp_key->mask_sz = node->mask_sz; tmp_key->proto = node->proto; *key_ptr = tmp_key; return STATUS_SUCCESS; omem: sepol_node_key_free(tmp_key); ERR(handle, "out of memory, could not extract node key"); return STATUS_ERR; } void sepol_node_key_free(sepol_node_key_t * key) { if (!key) return; free(key->addr); free(key->mask); free(key); } hidden_def(sepol_node_key_free) int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key) { int rc1, rc2; if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz)) return -1; else if ((node->addr_sz > key->addr_sz) || (node->mask_sz > key->mask_sz)) return 1; rc1 = memcmp(node->addr, key->addr, node->addr_sz); rc2 = memcmp(node->mask, key->mask, node->mask_sz); return (rc2 != 0) ? rc2 : rc1; } int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2) { int rc1, rc2; if ((node->addr_sz < node2->addr_sz) || (node->mask_sz < node2->mask_sz)) return -1; else if ((node->addr_sz > node2->addr_sz) || (node->mask_sz > node2->mask_sz)) return 1; rc1 = memcmp(node->addr, node2->addr, node->addr_sz); rc2 = memcmp(node->mask, node2->mask, node->mask_sz); return (rc2 != 0) ? rc2 : rc1; } /* Addr */ int sepol_node_get_addr(sepol_handle_t * handle, const sepol_node_t * node, char **addr) { char *tmp_addr = NULL; if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0) goto err; if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0) goto err; *addr = tmp_addr; return STATUS_SUCCESS; err: free(tmp_addr); ERR(handle, "could not get node address"); return STATUS_ERR; } hidden_def(sepol_node_get_addr) int sepol_node_get_addr_bytes(sepol_handle_t * handle, const sepol_node_t * node, char **buffer, size_t * bsize) { char *tmp_buf = malloc(node->addr_sz); if (!tmp_buf) { ERR(handle, "out of memory, could not get address bytes"); return STATUS_ERR; } memcpy(tmp_buf, node->addr, node->addr_sz); *buffer = tmp_buf; *bsize = node->addr_sz; return STATUS_SUCCESS; } hidden_def(sepol_node_get_addr_bytes) int sepol_node_set_addr(sepol_handle_t * handle, sepol_node_t * node, int proto, const char *addr) { char *tmp_addr = NULL; size_t tmp_addr_sz; if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0) goto err; if (node_parse_addr(handle, addr, proto, tmp_addr) < 0) goto err; free(node->addr); node->addr = tmp_addr; node->addr_sz = tmp_addr_sz; return STATUS_SUCCESS; err: free(tmp_addr); ERR(handle, "could not set node address to %s", addr); return STATUS_ERR; } hidden_def(sepol_node_set_addr) int sepol_node_set_addr_bytes(sepol_handle_t * handle, sepol_node_t * node, const char *addr, size_t addr_sz) { char *tmp_addr = malloc(addr_sz); if (!tmp_addr) { ERR(handle, "out of memory, could not " "set node address"); return STATUS_ERR; } memcpy(tmp_addr, addr, addr_sz); free(node->addr); node->addr = tmp_addr; node->addr_sz = addr_sz; return STATUS_SUCCESS; } hidden_def(sepol_node_set_addr_bytes) /* Mask */ int sepol_node_get_mask(sepol_handle_t * handle, const sepol_node_t * node, char **mask) { char *tmp_mask = NULL; if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0) goto err; if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0) goto err; *mask = tmp_mask; return STATUS_SUCCESS; err: free(tmp_mask); ERR(handle, "could not get node netmask"); return STATUS_ERR; } hidden_def(sepol_node_get_mask) int sepol_node_get_mask_bytes(sepol_handle_t * handle, const sepol_node_t * node, char **buffer, size_t * bsize) { char *tmp_buf = malloc(node->mask_sz); if (!tmp_buf) { ERR(handle, "out of memory, could not get netmask bytes"); return STATUS_ERR; } memcpy(tmp_buf, node->mask, node->mask_sz); *buffer = tmp_buf; *bsize = node->mask_sz; return STATUS_SUCCESS; } hidden_def(sepol_node_get_mask_bytes) int sepol_node_set_mask(sepol_handle_t * handle, sepol_node_t * node, int proto, const char *mask) { char *tmp_mask = NULL; size_t tmp_mask_sz; if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0) goto err; if (node_parse_addr(handle, mask, proto, tmp_mask) < 0) goto err; free(node->mask); node->mask = tmp_mask; node->mask_sz = tmp_mask_sz; return STATUS_SUCCESS; err: free(tmp_mask); ERR(handle, "could not set node netmask to %s", mask); return STATUS_ERR; } hidden_def(sepol_node_set_mask) int sepol_node_set_mask_bytes(sepol_handle_t * handle, sepol_node_t * node, const char *mask, size_t mask_sz) { char *tmp_mask = malloc(mask_sz); if (!tmp_mask) { ERR(handle, "out of memory, could not " "set node netmask"); return STATUS_ERR; } memcpy(tmp_mask, mask, mask_sz); free(node->mask); node->mask = tmp_mask; node->mask_sz = mask_sz; return STATUS_SUCCESS; } hidden_def(sepol_node_set_mask_bytes) /* Protocol */ int sepol_node_get_proto(const sepol_node_t * node) { return node->proto; } hidden_def(sepol_node_get_proto) void sepol_node_set_proto(sepol_node_t * node, int proto) { node->proto = proto; } hidden_def(sepol_node_set_proto) const char *sepol_node_get_proto_str(int proto) { switch (proto) { case SEPOL_PROTO_IP4: return "ipv4"; case SEPOL_PROTO_IP6: return "ipv6"; default: return "???"; } } hidden_def(sepol_node_get_proto_str) /* Create */ int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node) { sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t)); if (!tmp_node) { ERR(handle, "out of memory, could not create " "node record"); return STATUS_ERR; } tmp_node->addr = NULL; tmp_node->addr_sz = 0; tmp_node->mask = NULL; tmp_node->mask_sz = 0; tmp_node->proto = SEPOL_PROTO_IP4; tmp_node->con = NULL; *node = tmp_node; return STATUS_SUCCESS; } hidden_def(sepol_node_create) /* Deep copy clone */ int sepol_node_clone(sepol_handle_t * handle, const sepol_node_t * node, sepol_node_t ** node_ptr) { sepol_node_t *new_node = NULL; if (sepol_node_create(handle, &new_node) < 0) goto err; /* Copy address, mask, protocol */ new_node->addr = malloc(node->addr_sz); new_node->mask = malloc(node->mask_sz); if (!new_node->addr || !new_node->mask) goto omem; memcpy(new_node->addr, node->addr, node->addr_sz); memcpy(new_node->mask, node->mask, node->mask_sz); new_node->addr_sz = node->addr_sz; new_node->mask_sz = node->mask_sz; new_node->proto = node->proto; /* Copy context */ if (node->con && (sepol_context_clone(handle, node->con, &new_node->con) < 0)) goto err; *node_ptr = new_node; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not clone node record"); sepol_node_free(new_node); return STATUS_ERR; } /* Destroy */ void sepol_node_free(sepol_node_t * node) { if (!node) return; sepol_context_free(node->con); free(node->addr); free(node->mask); free(node); } hidden_def(sepol_node_free) /* Context */ sepol_context_t *sepol_node_get_con(const sepol_node_t * node) { return node->con; } hidden_def(sepol_node_get_con) int sepol_node_set_con(sepol_handle_t * handle, sepol_node_t * node, sepol_context_t * con) { sepol_context_t *newcon; if (sepol_context_clone(handle, con, &newcon) < 0) { ERR(handle, "out of memory, could not set node context"); return STATUS_ERR; } sepol_context_free(node->con); node->con = newcon; return STATUS_SUCCESS; } hidden_def(sepol_node_set_con) libsepol-2.2/src/nodes.c000066400000000000000000000207231223423440700152360ustar00rootroot00000000000000#include #include #include #include "debug.h" #include "context.h" #include "handle.h" #include #include "node_internal.h" /* Create a low level node structure from * a high level representation */ static int node_from_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t ** node, const sepol_node_t * data) { ocontext_t *tmp_node = NULL; context_struct_t *tmp_con = NULL; char *addr_buf = NULL, *mask_buf = NULL; tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t)); if (!tmp_node) goto omem; size_t addr_bsize, mask_bsize; /* Address and netmask */ if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0) goto err; if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0) goto err; int proto = sepol_node_get_proto(data); switch (proto) { case SEPOL_PROTO_IP4: memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize); memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize); break; case SEPOL_PROTO_IP6: memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize); memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize); break; default: ERR(handle, "unsupported protocol %u", proto); goto err; } free(addr_buf); free(mask_buf); addr_buf = NULL; mask_buf = NULL; /* Context */ if (context_from_record(handle, policydb, &tmp_con, sepol_node_get_con(data)) < 0) goto err; context_cpy(&tmp_node->context[0], tmp_con); context_destroy(tmp_con); free(tmp_con); tmp_con = NULL; *node = tmp_node; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: if (tmp_node != NULL) { context_destroy(&tmp_node->context[0]); free(tmp_node); } context_destroy(tmp_con); free(tmp_con); free(addr_buf); free(mask_buf); ERR(handle, "could not create node structure"); return STATUS_ERR; } static int node_to_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t * node, int proto, sepol_node_t ** record) { context_struct_t *con = &node->context[0]; sepol_context_t *tmp_con = NULL; sepol_node_t *tmp_record = NULL; if (sepol_node_create(handle, &tmp_record) < 0) goto err; sepol_node_set_proto(tmp_record, proto); switch (proto) { case SEPOL_PROTO_IP4: if (sepol_node_set_addr_bytes(handle, tmp_record, (const char *)&node->u.node.addr, 4) < 0) goto err; if (sepol_node_set_mask_bytes(handle, tmp_record, (const char *)&node->u.node.mask, 4) < 0) goto err; break; case SEPOL_PROTO_IP6: if (sepol_node_set_addr_bytes(handle, tmp_record, (const char *)&node->u.node6.addr, 16) < 0) goto err; if (sepol_node_set_mask_bytes(handle, tmp_record, (const char *)&node->u.node6.mask, 16) < 0) goto err; break; default: ERR(handle, "unsupported protocol %u", proto); goto err; } if (context_to_record(handle, policydb, con, &tmp_con) < 0) goto err; if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0) goto err; sepol_context_free(tmp_con); *record = tmp_record; return STATUS_SUCCESS; err: ERR(handle, "could not convert node to record"); sepol_context_free(tmp_con); sepol_node_free(tmp_record); return STATUS_ERR; } /* Return the number of nodes */ extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, unsigned int *response) { unsigned int count = 0; ocontext_t *c, *head; const policydb_t *policydb = &p->p; head = policydb->ocontexts[OCON_NODE]; for (c = head; c != NULL; c = c->next) count++; head = policydb->ocontexts[OCON_NODE6]; for (c = head; c != NULL; c = c->next) count++; *response = count; handle = NULL; return STATUS_SUCCESS; } /* Check if a node exists */ int sepol_node_exists(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_node_key_t * key, int *response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; int proto; const char *addr, *mask; sepol_node_key_unpack(key, &addr, &mask, &proto); switch (proto) { case SEPOL_PROTO_IP4: { head = policydb->ocontexts[OCON_NODE]; for (c = head; c; c = c->next) { unsigned int *addr2 = &c->u.node.addr; unsigned int *mask2 = &c->u.node.mask; if (!memcmp(addr, addr2, 4) && !memcmp(mask, mask2, 4)) { *response = 1; return STATUS_SUCCESS; } } break; } case SEPOL_PROTO_IP6: { head = policydb->ocontexts[OCON_NODE6]; for (c = head; c; c = c->next) { unsigned int *addr2 = c->u.node6.addr; unsigned int *mask2 = c->u.node6.mask; if (!memcmp(addr, addr2, 16) && !memcmp(mask, mask2, 16)) { *response = 1; return STATUS_SUCCESS; } } break; } default: ERR(handle, "unsupported protocol %u", proto); goto err; } *response = 0; return STATUS_SUCCESS; err: ERR(handle, "could not check if node %s/%s (%s) exists", addr, mask, sepol_node_get_proto_str(proto)); return STATUS_ERR; } /* Query a node */ int sepol_node_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_node_key_t * key, sepol_node_t ** response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; int proto; const char *addr, *mask; sepol_node_key_unpack(key, &addr, &mask, &proto); switch (proto) { case SEPOL_PROTO_IP4: { head = policydb->ocontexts[OCON_NODE]; for (c = head; c; c = c->next) { unsigned int *addr2 = &c->u.node.addr; unsigned int *mask2 = &c->u.node.mask; if (!memcmp(addr, addr2, 4) && !memcmp(mask, mask2, 4)) { if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, response) < 0) goto err; return STATUS_SUCCESS; } } break; } case SEPOL_PROTO_IP6: { head = policydb->ocontexts[OCON_NODE6]; for (c = head; c; c = c->next) { unsigned int *addr2 = c->u.node6.addr; unsigned int *mask2 = c->u.node6.mask; if (!memcmp(addr, addr2, 16) && !memcmp(mask, mask2, 16)) { if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, response) < 0) goto err; } } break; } default: ERR(handle, "unsupported protocol %u", proto); goto err; } *response = NULL; return STATUS_SUCCESS; err: ERR(handle, "could not query node %s/%s (%s)", addr, mask, sepol_node_get_proto_str(proto)); return STATUS_ERR; } /* Load a node into policy */ int sepol_node_modify(sepol_handle_t * handle, sepol_policydb_t * p, const sepol_node_key_t * key, const sepol_node_t * data) { policydb_t *policydb = &p->p; ocontext_t *node = NULL; int proto; const char *addr, *mask; sepol_node_key_unpack(key, &addr, &mask, &proto); if (node_from_record(handle, policydb, &node, data) < 0) goto err; switch (proto) { case SEPOL_PROTO_IP4: { /* Attach to context list */ node->next = policydb->ocontexts[OCON_NODE]; policydb->ocontexts[OCON_NODE] = node; break; } case SEPOL_PROTO_IP6: { /* Attach to context list */ node->next = policydb->ocontexts[OCON_NODE6]; policydb->ocontexts[OCON_NODE6] = node; break; } default: ERR(handle, "unsupported protocol %u", proto); goto err; } return STATUS_SUCCESS; err: ERR(handle, "could not load node %s/%s (%s)", addr, mask, sepol_node_get_proto_str(proto)); if (node != NULL) { context_destroy(&node->context[0]); free(node); } return STATUS_ERR; } int sepol_node_iterate(sepol_handle_t * handle, const sepol_policydb_t * p, int (*fn) (const sepol_node_t * node, void *fn_arg), void *arg) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; sepol_node_t *node = NULL; int status; head = policydb->ocontexts[OCON_NODE]; for (c = head; c; c = c->next) { if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node) < 0) goto err; /* Invoke handler */ status = fn(node, arg); if (status < 0) goto err; sepol_node_free(node); node = NULL; /* Handler requested exit */ if (status > 0) break; } head = policydb->ocontexts[OCON_NODE6]; for (c = head; c; c = c->next) { if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node) < 0) goto err; /* Invoke handler */ status = fn(node, arg); if (status < 0) goto err; sepol_node_free(node); node = NULL; /* Handler requested exit */ if (status > 0) break; } return STATUS_SUCCESS; err: ERR(handle, "could not iterate over nodes"); sepol_node_free(node); return STATUS_ERR; } libsepol-2.2/src/polcaps.c000066400000000000000000000014251223423440700155650ustar00rootroot00000000000000/* * Policy capability support functions */ #include #include static const char *polcap_names[] = { "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */ "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */ "redhat1", /* POLICYDB_CAPABILITY_REDHAT1, aka ptrace_child */ "always_check_network", /* POLICYDB_CAPABILITY_ALWAYSNETWORK */ NULL }; int sepol_polcap_getnum(const char *name) { int capnum; for (capnum = 0; capnum <= POLICYDB_CAPABILITY_MAX; capnum++) { if (polcap_names[capnum] == NULL) continue; if (strcasecmp(polcap_names[capnum], name) == 0) return capnum; } return -1; } const char *sepol_polcap_getname(int capnum) { if (capnum > POLICYDB_CAPABILITY_MAX) return NULL; return polcap_names[capnum]; } libsepol-2.2/src/policydb.c000066400000000000000000002554771223423440700157530ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * * Updated: Red Hat, Inc. James Morris * Fine-grained netlink support * IPv6 support * Code cleanup * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2005 Tresys Technology, LLC * Copyright (C) 2003 - 2007 Red Hat, Inc. * * 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 */ /* FLASK */ /* * Implementation of the policy database. */ #include #include #include #include #include #include #include #include #include "private.h" #include "debug.h" #include "mls.h" #define POLICYDB_TARGET_SZ ARRAY_SIZE(policydb_target_strings) char *policydb_target_strings[] = { POLICYDB_STRING, POLICYDB_XEN_STRING }; /* These need to be updated if SYM_NUM or OCON_NUM changes */ static struct policydb_compat_info policydb_compat[] = { { .type = POLICY_KERN, .version = POLICYDB_VERSION_BOUNDARY, .sym_num = SYM_NUM, .ocon_num = OCON_XEN_PCIDEVICE + 1, .target_platform = SEPOL_TARGET_XEN, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_BASE, .sym_num = SYM_NUM - 3, .ocon_num = OCON_FSUSE + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_BOOL, .sym_num = SYM_NUM - 2, .ocon_num = OCON_FSUSE + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_IPV6, .sym_num = SYM_NUM - 2, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_NLCLASS, .sym_num = SYM_NUM - 2, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_MLS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_AVTAB, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_RANGETRANS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_PERMISSIVE, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_BOUNDARY, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_FILENAME_TRANS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_ROLETRANS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_DEFAULT_TYPE, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_KERN, .version = POLICYDB_VERSION_CONSTRAINT_NAMES, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BASE, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_MLS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_MLS_USERS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_PERMISSIVE, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BOUNDARY, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_FILENAME_TRANS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_ROLETRANS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_ROLEATTRIB, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_TUNABLE_SEP, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, .sym_num = SYM_NUM, .ocon_num = OCON_NODE6 + 1, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BASE, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_MLS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_MLS_USERS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_PERMISSIVE, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BOUNDARY, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BOUNDARY_ALIAS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_FILENAME_TRANS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_ROLETRANS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_ROLEATTRIB, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_TUNABLE_SEP, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, .sym_num = SYM_NUM, .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, }; #if 0 static char *symtab_name[SYM_NUM] = { "common prefixes", "classes", "roles", "types", "users", "bools" mls_symtab_names cond_symtab_names }; #endif static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, 16, 512, 128, 16, 16, 16, }; struct policydb_compat_info *policydb_lookup_compat(unsigned int version, unsigned int type, unsigned int target_platform) { unsigned int i; struct policydb_compat_info *info = NULL; for (i = 0; i < sizeof(policydb_compat) / sizeof(*info); i++) { if (policydb_compat[i].version == version && policydb_compat[i].type == type && policydb_compat[i].target_platform == target_platform) { info = &policydb_compat[i]; break; } } return info; } void type_set_init(type_set_t * x) { memset(x, 0, sizeof(type_set_t)); ebitmap_init(&x->types); ebitmap_init(&x->negset); } void type_set_destroy(type_set_t * x) { if (x != NULL) { ebitmap_destroy(&x->types); ebitmap_destroy(&x->negset); } } void role_set_init(role_set_t * x) { memset(x, 0, sizeof(role_set_t)); ebitmap_init(&x->roles); } void role_set_destroy(role_set_t * x) { ebitmap_destroy(&x->roles); } void role_datum_init(role_datum_t * x) { memset(x, 0, sizeof(role_datum_t)); ebitmap_init(&x->dominates); type_set_init(&x->types); ebitmap_init(&x->cache); ebitmap_init(&x->roles); } void role_datum_destroy(role_datum_t * x) { if (x != NULL) { ebitmap_destroy(&x->dominates); type_set_destroy(&x->types); ebitmap_destroy(&x->cache); ebitmap_destroy(&x->roles); } } void type_datum_init(type_datum_t * x) { memset(x, 0, sizeof(*x)); ebitmap_init(&x->types); } void type_datum_destroy(type_datum_t * x) { if (x != NULL) { ebitmap_destroy(&x->types); } } void user_datum_init(user_datum_t * x) { memset(x, 0, sizeof(user_datum_t)); role_set_init(&x->roles); mls_semantic_range_init(&x->range); mls_semantic_level_init(&x->dfltlevel); ebitmap_init(&x->cache); mls_range_init(&x->exp_range); mls_level_init(&x->exp_dfltlevel); } void user_datum_destroy(user_datum_t * x) { if (x != NULL) { role_set_destroy(&x->roles); mls_semantic_range_destroy(&x->range); mls_semantic_level_destroy(&x->dfltlevel); ebitmap_destroy(&x->cache); mls_range_destroy(&x->exp_range); mls_level_destroy(&x->exp_dfltlevel); } } void level_datum_init(level_datum_t * x) { memset(x, 0, sizeof(level_datum_t)); } void level_datum_destroy(level_datum_t * x __attribute__ ((unused))) { /* the mls_level_t referenced by the level_datum is managed * separately for now, so there is nothing to destroy */ return; } void cat_datum_init(cat_datum_t * x) { memset(x, 0, sizeof(cat_datum_t)); } void cat_datum_destroy(cat_datum_t * x __attribute__ ((unused))) { /* it's currently a simple struct - really nothing to destroy */ return; } void class_perm_node_init(class_perm_node_t * x) { memset(x, 0, sizeof(class_perm_node_t)); } void avrule_init(avrule_t * x) { memset(x, 0, sizeof(avrule_t)); type_set_init(&x->stypes); type_set_init(&x->ttypes); } void avrule_destroy(avrule_t * x) { class_perm_node_t *cur, *next; if (x == NULL) { return; } type_set_destroy(&x->stypes); type_set_destroy(&x->ttypes); next = x->perms; while (next) { cur = next; next = cur->next; free(cur); } } void role_trans_rule_init(role_trans_rule_t * x) { memset(x, 0, sizeof(*x)); role_set_init(&x->roles); type_set_init(&x->types); ebitmap_init(&x->classes); } void role_trans_rule_destroy(role_trans_rule_t * x) { if (x != NULL) { role_set_destroy(&x->roles); type_set_destroy(&x->types); ebitmap_destroy(&x->classes); } } void role_trans_rule_list_destroy(role_trans_rule_t * x) { while (x != NULL) { role_trans_rule_t *next = x->next; role_trans_rule_destroy(x); free(x); x = next; } } void filename_trans_rule_init(filename_trans_rule_t * x) { memset(x, 0, sizeof(*x)); type_set_init(&x->stypes); type_set_init(&x->ttypes); } static void filename_trans_rule_destroy(filename_trans_rule_t * x) { if (!x) return; type_set_destroy(&x->stypes); type_set_destroy(&x->ttypes); free(x->name); } void filename_trans_rule_list_destroy(filename_trans_rule_t * x) { filename_trans_rule_t *next; while (x) { next = x->next; filename_trans_rule_destroy(x); free(x); x = next; } } void role_allow_rule_init(role_allow_rule_t * x) { memset(x, 0, sizeof(role_allow_rule_t)); role_set_init(&x->roles); role_set_init(&x->new_roles); } void role_allow_rule_destroy(role_allow_rule_t * x) { role_set_destroy(&x->roles); role_set_destroy(&x->new_roles); } void role_allow_rule_list_destroy(role_allow_rule_t * x) { while (x != NULL) { role_allow_rule_t *next = x->next; role_allow_rule_destroy(x); free(x); x = next; } } void range_trans_rule_init(range_trans_rule_t * x) { type_set_init(&x->stypes); type_set_init(&x->ttypes); ebitmap_init(&x->tclasses); mls_semantic_range_init(&x->trange); x->next = NULL; } void range_trans_rule_destroy(range_trans_rule_t * x) { type_set_destroy(&x->stypes); type_set_destroy(&x->ttypes); ebitmap_destroy(&x->tclasses); mls_semantic_range_destroy(&x->trange); } void range_trans_rule_list_destroy(range_trans_rule_t * x) { while (x != NULL) { range_trans_rule_t *next = x->next; range_trans_rule_destroy(x); free(x); x = next; } } void avrule_list_destroy(avrule_t * x) { avrule_t *next, *cur; if (!x) return; next = x; while (next) { cur = next; next = next->next; avrule_destroy(cur); free(cur); } } /* * Initialize the role table by implicitly adding role 'object_r'. If * the policy is a module, set object_r's scope to be SCOPE_REQ, * otherwise set it to SCOPE_DECL. */ static int roles_init(policydb_t * p) { char *key = 0; int rc; role_datum_t *role; role = calloc(1, sizeof(role_datum_t)); if (!role) { rc = -ENOMEM; goto out; } key = malloc(strlen(OBJECT_R) + 1); if (!key) { rc = -ENOMEM; goto out_free_role; } strcpy(key, OBJECT_R); rc = symtab_insert(p, SYM_ROLES, key, role, (p->policy_type == POLICY_MOD ? SCOPE_REQ : SCOPE_DECL), 1, &role->s.value); if (rc) goto out_free_key; if (role->s.value != OBJECT_R_VAL) { rc = -EINVAL; goto out_free_role; } out: return rc; out_free_key: free(key); out_free_role: free(role); goto out; } /* * Initialize a policy database structure. */ int policydb_init(policydb_t * p) { int i, rc; memset(p, 0, sizeof(policydb_t)); ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); for (i = 0; i < SYM_NUM; i++) { p->sym_val_to_name[i] = NULL; rc = symtab_init(&p->symtab[i], symtab_sizes[i]); if (rc) goto out_free_symtab; } /* initialize the module stuff */ for (i = 0; i < SYM_NUM; i++) { if (symtab_init(&p->scope[i], symtab_sizes[i])) { goto out_free_symtab; } } if ((p->global = avrule_block_create()) == NULL || (p->global->branch_list = avrule_decl_create(1)) == NULL) { goto out_free_symtab; } p->decl_val_to_struct = NULL; rc = avtab_init(&p->te_avtab); if (rc) goto out_free_symtab; rc = roles_init(p); if (rc) goto out_free_symtab; rc = cond_policydb_init(p); if (rc) goto out_free_symtab; out: return rc; out_free_symtab: for (i = 0; i < SYM_NUM; i++) { hashtab_destroy(p->symtab[i].table); hashtab_destroy(p->scope[i].table); } avrule_block_list_destroy(p->global); goto out; } int policydb_role_cache(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *arg) { policydb_t *p; role_datum_t *role; role = (role_datum_t *) datum; p = (policydb_t *) arg; ebitmap_destroy(&role->cache); if (type_set_expand(&role->types, &role->cache, p, 1)) { return -1; } return 0; } int policydb_user_cache(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *arg) { policydb_t *p; user_datum_t *user; user = (user_datum_t *) datum; p = (policydb_t *) arg; ebitmap_destroy(&user->cache); if (role_set_expand(&user->roles, &user->cache, p, NULL, NULL)) { return -1; } /* we do not expand user's MLS info in kernel policies because the * semantic representation is not present and we do not expand user's * MLS info in module policies because all of the necessary mls * information is not present */ if (p->policy_type != POLICY_KERN && p->policy_type != POLICY_MOD) { mls_range_destroy(&user->exp_range); if (mls_semantic_range_expand(&user->range, &user->exp_range, p, NULL)) { return -1; } mls_level_destroy(&user->exp_dfltlevel); if (mls_semantic_level_expand(&user->dfltlevel, &user->exp_dfltlevel, p, NULL)) { return -1; } } return 0; } /* * The following *_index functions are used to * define the val_to_name and val_to_struct arrays * in a policy database structure. The val_to_name * arrays are used when converting security context * structures into string representations. The * val_to_struct arrays are used when the attributes * of a class, role, or user are needed. */ static int common_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; common_datum_t *comdatum; comdatum = (common_datum_t *) datum; p = (policydb_t *) datap; if (!comdatum->s.value || comdatum->s.value > p->p_commons.nprim) return -EINVAL; p->p_common_val_to_name[comdatum->s.value - 1] = (char *)key; return 0; } static int class_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; class_datum_t *cladatum; cladatum = (class_datum_t *) datum; p = (policydb_t *) datap; if (!cladatum->s.value || cladatum->s.value > p->p_classes.nprim) return -EINVAL; p->p_class_val_to_name[cladatum->s.value - 1] = (char *)key; p->class_val_to_struct[cladatum->s.value - 1] = cladatum; return 0; } static int role_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; role_datum_t *role; role = (role_datum_t *) datum; p = (policydb_t *) datap; if (!role->s.value || role->s.value > p->p_roles.nprim) return -EINVAL; p->p_role_val_to_name[role->s.value - 1] = (char *)key; p->role_val_to_struct[role->s.value - 1] = role; return 0; } static int type_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; type_datum_t *typdatum; typdatum = (type_datum_t *) datum; p = (policydb_t *) datap; if (typdatum->primary) { if (!typdatum->s.value || typdatum->s.value > p->p_types.nprim) return -EINVAL; p->p_type_val_to_name[typdatum->s.value - 1] = (char *)key; p->type_val_to_struct[typdatum->s.value - 1] = typdatum; } return 0; } static int user_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; user_datum_t *usrdatum; usrdatum = (user_datum_t *) datum; p = (policydb_t *) datap; if (!usrdatum->s.value || usrdatum->s.value > p->p_users.nprim) return -EINVAL; p->p_user_val_to_name[usrdatum->s.value - 1] = (char *)key; p->user_val_to_struct[usrdatum->s.value - 1] = usrdatum; return 0; } static int sens_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; level_datum_t *levdatum; levdatum = (level_datum_t *) datum; p = (policydb_t *) datap; if (!levdatum->isalias) { if (!levdatum->level->sens || levdatum->level->sens > p->p_levels.nprim) return -EINVAL; p->p_sens_val_to_name[levdatum->level->sens - 1] = (char *)key; } return 0; } static int cat_index(hashtab_key_t key, hashtab_datum_t datum, void *datap) { policydb_t *p; cat_datum_t *catdatum; catdatum = (cat_datum_t *) datum; p = (policydb_t *) datap; if (!catdatum->isalias) { if (!catdatum->s.value || catdatum->s.value > p->p_cats.nprim) return -EINVAL; p->p_cat_val_to_name[catdatum->s.value - 1] = (char *)key; } return 0; } static int (*index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) = { common_index, class_index, role_index, type_index, user_index, cond_index_bool, sens_index, cat_index,}; /* * Define the common val_to_name array and the class * val_to_name and val_to_struct arrays in a policy * database structure. */ int policydb_index_classes(policydb_t * p) { free(p->p_common_val_to_name); p->p_common_val_to_name = (char **) malloc(p->p_commons.nprim * sizeof(char *)); if (!p->p_common_val_to_name) return -1; if (hashtab_map(p->p_commons.table, common_index, p)) return -1; free(p->class_val_to_struct); p->class_val_to_struct = (class_datum_t **) malloc(p->p_classes.nprim * sizeof(class_datum_t *)); if (!p->class_val_to_struct) return -1; free(p->p_class_val_to_name); p->p_class_val_to_name = (char **) malloc(p->p_classes.nprim * sizeof(char *)); if (!p->p_class_val_to_name) return -1; if (hashtab_map(p->p_classes.table, class_index, p)) return -1; return 0; } int policydb_index_bools(policydb_t * p) { if (cond_init_bool_indexes(p) == -1) return -1; p->p_bool_val_to_name = (char **) malloc(p->p_bools.nprim * sizeof(char *)); if (!p->p_bool_val_to_name) return -1; if (hashtab_map(p->p_bools.table, cond_index_bool, p)) return -1; return 0; } int policydb_index_decls(policydb_t * p) { avrule_block_t *curblock; avrule_decl_t *decl; int num_decls = 0; free(p->decl_val_to_struct); for (curblock = p->global; curblock != NULL; curblock = curblock->next) { for (decl = curblock->branch_list; decl != NULL; decl = decl->next) { num_decls++; } } p->decl_val_to_struct = calloc(num_decls, sizeof(*(p->decl_val_to_struct))); if (!p->decl_val_to_struct) { return -1; } for (curblock = p->global; curblock != NULL; curblock = curblock->next) { for (decl = curblock->branch_list; decl != NULL; decl = decl->next) { p->decl_val_to_struct[decl->decl_id - 1] = decl; } } return 0; } /* * Define the other val_to_name and val_to_struct arrays * in a policy database structure. */ int policydb_index_others(sepol_handle_t * handle, policydb_t * p, unsigned verbose) { int i; if (verbose) { INFO(handle, "security: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); if (p->mls) INFO(handle, "security: %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); INFO(handle, "security: %d classes, %d rules, %d cond rules", p->p_classes.nprim, p->te_avtab.nel, p->te_cond_avtab.nel); } #if 0 avtab_hash_eval(&p->te_avtab, "rules"); for (i = 0; i < SYM_NUM; i++) hashtab_hash_eval(p->symtab[i].table, symtab_name[i]); #endif free(p->role_val_to_struct); p->role_val_to_struct = (role_datum_t **) malloc(p->p_roles.nprim * sizeof(role_datum_t *)); if (!p->role_val_to_struct) return -1; free(p->user_val_to_struct); p->user_val_to_struct = (user_datum_t **) malloc(p->p_users.nprim * sizeof(user_datum_t *)); if (!p->user_val_to_struct) return -1; free(p->type_val_to_struct); p->type_val_to_struct = (type_datum_t **) calloc(p->p_types.nprim, sizeof(type_datum_t *)); if (!p->type_val_to_struct) return -1; cond_init_bool_indexes(p); for (i = SYM_ROLES; i < SYM_NUM; i++) { free(p->sym_val_to_name[i]); p->sym_val_to_name[i] = NULL; if (p->symtab[i].nprim) { p->sym_val_to_name[i] = (char **) calloc(p->symtab[i].nprim, sizeof(char *)); if (!p->sym_val_to_name[i]) return -1; if (hashtab_map(p->symtab[i].table, index_f[i], p)) return -1; } } /* This pre-expands the roles and users for context validity checking */ if (hashtab_map(p->p_roles.table, policydb_role_cache, p)) return -1; if (hashtab_map(p->p_users.table, policydb_user_cache, p)) return -1; return 0; } /* * The following *_destroy functions are used to * free any memory allocated for each kind of * symbol data in the policy database. */ 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 int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { common_datum_t *comdatum; if (key) free(key); comdatum = (common_datum_t *) datum; (void)hashtab_map(comdatum->permissions.table, perm_destroy, 0); hashtab_destroy(comdatum->permissions.table); free(datum); return 0; } static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { class_datum_t *cladatum; constraint_node_t *constraint, *ctemp; constraint_expr_t *e, *etmp; if (key) free(key); cladatum = (class_datum_t *) datum; if (cladatum == NULL) { return 0; } (void)hashtab_map(cladatum->permissions.table, perm_destroy, 0); hashtab_destroy(cladatum->permissions.table); constraint = cladatum->constraints; while (constraint) { e = constraint->expr; while (e) { etmp = e; e = e->next; constraint_expr_destroy(etmp); } ctemp = constraint; constraint = constraint->next; free(ctemp); } constraint = cladatum->validatetrans; while (constraint) { e = constraint->expr; while (e) { etmp = e; e = e->next; constraint_expr_destroy(etmp); } ctemp = constraint; constraint = constraint->next; free(ctemp); } if (cladatum->comkey) free(cladatum->comkey); free(datum); return 0; } static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { free(key); role_datum_destroy((role_datum_t *) datum); free(datum); return 0; } static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { free(key); type_datum_destroy((type_datum_t *) datum); free(datum); return 0; } static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { free(key); user_datum_destroy((user_datum_t *) datum); free(datum); return 0; } static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { level_datum_t *levdatum; if (key) free(key); levdatum = (level_datum_t *) datum; mls_level_destroy(levdatum->level); free(levdatum->level); level_datum_destroy(levdatum); free(levdatum); return 0; } static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { if (key) free(key); cat_datum_destroy((cat_datum_t *) datum); free(datum); return 0; } static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) = { common_destroy, class_destroy, role_destroy, type_destroy, user_destroy, cond_destroy_bool, sens_destroy, cat_destroy,}; void ocontext_selinux_free(ocontext_t **ocontexts) { ocontext_t *c, *ctmp; int i; for (i = 0; i < OCON_NUM; i++) { c = ocontexts[i]; while (c) { ctmp = c; c = c->next; context_destroy(&ctmp->context[0]); context_destroy(&ctmp->context[1]); if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF || i == OCON_FSUSE) free(ctmp->u.name); free(ctmp); } } } void ocontext_xen_free(ocontext_t **ocontexts) { ocontext_t *c, *ctmp; int i; for (i = 0; i < OCON_NUM; i++) { c = ocontexts[i]; while (c) { ctmp = c; c = c->next; context_destroy(&ctmp->context[0]); context_destroy(&ctmp->context[1]); if (i == OCON_ISID) free(ctmp->u.name); free(ctmp); } } } /* * Free any memory allocated by a policy database structure. */ void policydb_destroy(policydb_t * p) { ocontext_t *c, *ctmp; genfs_t *g, *gtmp; unsigned int i; role_allow_t *ra, *lra = NULL; role_trans_t *tr, *ltr = NULL; range_trans_t *rt, *lrt = NULL; filename_trans_t *ft, *nft; if (!p) return; ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->permissive_map); symtabs_destroy(p->symtab); for (i = 0; i < SYM_NUM; i++) { if (p->sym_val_to_name[i]) free(p->sym_val_to_name[i]); } if (p->class_val_to_struct) free(p->class_val_to_struct); if (p->role_val_to_struct) free(p->role_val_to_struct); if (p->user_val_to_struct) free(p->user_val_to_struct); if (p->type_val_to_struct) free(p->type_val_to_struct); free(p->decl_val_to_struct); for (i = 0; i < SYM_NUM; i++) { (void)hashtab_map(p->scope[i].table, scope_destroy, 0); hashtab_destroy(p->scope[i].table); } avrule_block_list_destroy(p->global); free(p->name); free(p->version); avtab_destroy(&p->te_avtab); if (p->target_platform == SEPOL_TARGET_SELINUX) ocontext_selinux_free(p->ocontexts); else if (p->target_platform == SEPOL_TARGET_XEN) ocontext_xen_free(p->ocontexts); g = p->genfs; while (g) { free(g->fstype); c = g->head; while (c) { ctmp = c; c = c->next; context_destroy(&ctmp->context[0]); free(ctmp->u.name); free(ctmp); } gtmp = g; g = g->next; free(gtmp); } cond_policydb_destroy(p); for (tr = p->role_tr; tr; tr = tr->next) { if (ltr) free(ltr); ltr = tr; } if (ltr) free(ltr); ft = p->filename_trans; while (ft) { nft = ft->next; free(ft->name); free(ft); ft = nft; } for (ra = p->role_allow; ra; ra = ra->next) { if (lra) free(lra); lra = ra; } if (lra) free(lra); for (rt = p->range_tr; rt; rt = rt->next) { if (lrt) { ebitmap_destroy(&lrt->target_range.level[0].cat); ebitmap_destroy(&lrt->target_range.level[1].cat); free(lrt); } lrt = rt; } if (lrt) { ebitmap_destroy(&lrt->target_range.level[0].cat); ebitmap_destroy(&lrt->target_range.level[1].cat); free(lrt); } if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) { ebitmap_destroy(&p->type_attr_map[i]); } free(p->type_attr_map); } if (p->attr_type_map) { for (i = 0; i < p->p_types.nprim; i++) { ebitmap_destroy(&p->attr_type_map[i]); } free(p->attr_type_map); } return; } void symtabs_destroy(symtab_t * symtab) { int i; for (i = 0; i < SYM_NUM; i++) { (void)hashtab_map(symtab[i].table, destroy_f[i], 0); hashtab_destroy(symtab[i].table); } } int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { scope_datum_t *cur = (scope_datum_t *) datum; free(key); if (cur != NULL) { free(cur->decl_ids); } free(cur); return 0; } hashtab_destroy_func_t get_symtab_destroy_func(int sym_num) { if (sym_num < 0 || sym_num >= SYM_NUM) { return NULL; } return (hashtab_destroy_func_t) destroy_f[sym_num]; } /* * Load the initial SIDs specified in a policy database * structure into a SID table. */ int policydb_load_isids(policydb_t * p, sidtab_t * s) { ocontext_t *head, *c; if (sepol_sidtab_init(s)) { ERR(NULL, "out of memory on SID table init"); return -1; } head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { if (!c->context[0].user) { ERR(NULL, "SID %s was never defined", c->u.name); return -1; } if (sepol_sidtab_insert(s, c->sid[0], &c->context[0])) { ERR(NULL, "unable to load initial SID %s", c->u.name); return -1; } } return 0; } /* Declare a symbol for a certain avrule_block context. Insert it * into a symbol table for a policy. This function will handle * inserting the appropriate scope information in addition to * inserting the symbol into the hash table. * * arguments: * policydb_t *pol module policy to modify * uint32_t sym the symbole table for insertion (SYM_*) * hashtab_key_t key the key for the symbol - not cloned * hashtab_datum_t data the data for the symbol - not cloned * scope scope of this symbol, either SCOPE_REQ or SCOPE_DECL * avrule_decl_id identifier for this symbol's encapsulating declaration * value (out) assigned value to the symbol (if value is not NULL) * * returns: * 0 success * 1 success, but symbol already existed as a requirement * (datum was not inserted and needs to be free()d) * -1 general error * -2 scope conflicted * -ENOMEM memory error * error codes from hashtab_insert */ int symtab_insert(policydb_t * pol, uint32_t sym, hashtab_key_t key, hashtab_datum_t datum, uint32_t scope, uint32_t avrule_decl_id, uint32_t * value) { int rc, retval = 0; unsigned int i; scope_datum_t *scope_datum; /* check if the symbol is already there. multiple * declarations of non-roles/non-users are illegal, but * multiple requires are allowed. */ /* FIX ME - the failures after the hashtab_insert will leave * the policy in a inconsistent state. */ rc = hashtab_insert(pol->symtab[sym].table, key, datum); if (rc == SEPOL_OK) { /* if no value is passed in the symbol is not primary * (i.e. aliases) */ if (value) *value = ++pol->symtab[sym].nprim; } else if (rc == SEPOL_EEXIST) { retval = 1; /* symbol not added -- need to free() later */ } else { return rc; } /* get existing scope information; if there is not one then * create it */ scope_datum = (scope_datum_t *) hashtab_search(pol->scope[sym].table, key); if (scope_datum == NULL) { hashtab_key_t key2 = strdup((char *)key); if (!key2) return -ENOMEM; if ((scope_datum = malloc(sizeof(*scope_datum))) == NULL) { free(key2); return -ENOMEM; } scope_datum->scope = scope; scope_datum->decl_ids = NULL; scope_datum->decl_ids_len = 0; if ((rc = hashtab_insert(pol->scope[sym].table, key2, scope_datum)) != 0) { free(key2); free(scope_datum); return rc; } } else if (scope_datum->scope == SCOPE_DECL && scope == SCOPE_DECL) { /* disallow multiple declarations for non-roles/users */ if (sym != SYM_ROLES && sym != SYM_USERS) { return -2; } /* Further confine that a role attribute can't have the same * name as another regular role, and a role attribute can't * be declared more than once. */ if (sym == SYM_ROLES) { role_datum_t *base_role; role_datum_t *cur_role = (role_datum_t *)datum; base_role = (role_datum_t *) hashtab_search(pol->symtab[sym].table, key); assert(base_role != NULL); if (!((base_role->flavor == ROLE_ROLE) && (cur_role->flavor == ROLE_ROLE))) { /* Only regular roles are allowed to have * multiple declarations. */ return -2; } } } else if (scope_datum->scope == SCOPE_REQ && scope == SCOPE_DECL) { scope_datum->scope = SCOPE_DECL; } else if (scope_datum->scope != scope) { /* This only happens in DECL then REQUIRE case, which is handled by caller */ return -2; } /* search through the pre-existing list to avoid adding duplicates */ for (i = 0; i < scope_datum->decl_ids_len; i++) { if (scope_datum->decl_ids[i] == avrule_decl_id) { /* already there, so don't modify its scope */ return retval; } } if (add_i_to_a(avrule_decl_id, &scope_datum->decl_ids_len, &scope_datum->decl_ids) == -1) { return -ENOMEM; } return retval; } int type_set_or(type_set_t * dst, type_set_t * a, type_set_t * b) { type_set_init(dst); if (ebitmap_or(&dst->types, &a->types, &b->types)) { return -1; } if (ebitmap_or(&dst->negset, &a->negset, &b->negset)) { return -1; } dst->flags |= a->flags; dst->flags |= b->flags; return 0; } int type_set_cpy(type_set_t * dst, type_set_t * src) { type_set_init(dst); dst->flags = src->flags; if (ebitmap_cpy(&dst->types, &src->types)) return -1; if (ebitmap_cpy(&dst->negset, &src->negset)) return -1; return 0; } int type_set_or_eq(type_set_t * dst, type_set_t * other) { int ret; type_set_t tmp; if (type_set_or(&tmp, dst, other)) return -1; type_set_destroy(dst); ret = type_set_cpy(dst, &tmp); type_set_destroy(&tmp); return ret; } int role_set_get_role(role_set_t * x, uint32_t role) { if (x->flags & ROLE_STAR) return 1; if (ebitmap_get_bit(&x->roles, role - 1)) { if (x->flags & ROLE_COMP) return 0; else return 1; } else { if (x->flags & ROLE_COMP) return 1; else return 0; } } /***********************************************************************/ /* everything below is for policy reads */ /* The following are read functions for module structures */ static int role_set_read(role_set_t * r, struct policy_file *fp) { uint32_t buf[1]; int rc; if (ebitmap_read(&r->roles, fp)) return -1; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; r->flags = le32_to_cpu(buf[0]); return 0; } static int type_set_read(type_set_t * t, struct policy_file *fp) { uint32_t buf[1]; int rc; if (ebitmap_read(&t->types, fp)) return -1; if (ebitmap_read(&t->negset, fp)) return -1; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; t->flags = le32_to_cpu(buf[0]); return 0; } /* * Read a MLS range structure from a policydb binary * representation file. */ static int mls_read_range_helper(mls_range_t * r, struct policy_file *fp) { uint32_t buf[2], items; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto out; items = le32_to_cpu(buf[0]); if (items > ARRAY_SIZE(buf)) { ERR(fp->handle, "range overflow"); rc = -EINVAL; goto out; } rc = next_entry(buf, fp, sizeof(uint32_t) * items); if (rc < 0) { ERR(fp->handle, "truncated range"); goto out; } r->level[0].sens = le32_to_cpu(buf[0]); if (items > 1) r->level[1].sens = le32_to_cpu(buf[1]); else r->level[1].sens = r->level[0].sens; rc = ebitmap_read(&r->level[0].cat, fp); if (rc) { ERR(fp->handle, "error reading low categories"); goto out; } if (items > 1) { rc = ebitmap_read(&r->level[1].cat, fp); if (rc) { ERR(fp->handle, "error reading high categories"); goto bad_high; } } else { rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); if (rc) { ERR(fp->handle, "out of memory"); goto bad_high; } } rc = 0; out: return rc; bad_high: ebitmap_destroy(&r->level[0].cat); goto out; } /* * Read a semantic MLS level structure from a policydb binary * representation file. */ static int mls_read_semantic_level_helper(mls_semantic_level_t * l, struct policy_file *fp) { uint32_t buf[2], ncat; unsigned int i; mls_semantic_cat_t *cat; int rc; mls_semantic_level_init(l); rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) { ERR(fp->handle, "truncated level"); goto bad; } l->sens = le32_to_cpu(buf[0]); ncat = le32_to_cpu(buf[1]); for (i = 0; i < ncat; i++) { cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); if (!cat) { ERR(fp->handle, "out of memory"); goto bad; } mls_semantic_cat_init(cat); cat->next = l->cat; l->cat = cat; rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) { ERR(fp->handle, "error reading level categories"); goto bad; } cat->low = le32_to_cpu(buf[0]); cat->high = le32_to_cpu(buf[1]); } return 0; bad: return -EINVAL; } /* * Read a semantic MLS range structure from a policydb binary * representation file. */ static int mls_read_semantic_range_helper(mls_semantic_range_t * r, struct policy_file *fp) { int rc; rc = mls_read_semantic_level_helper(&r->level[0], fp); if (rc) return rc; rc = mls_read_semantic_level_helper(&r->level[1], fp); return rc; } static int mls_level_to_semantic(mls_level_t * l, mls_semantic_level_t * sl) { unsigned int i; ebitmap_node_t *cnode; mls_semantic_cat_t *open_cat = NULL; mls_semantic_level_init(sl); sl->sens = l->sens; ebitmap_for_each_bit(&l->cat, cnode, i) { if (ebitmap_node_get_bit(cnode, i)) { if (open_cat) continue; open_cat = (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t)); if (!open_cat) return -1; mls_semantic_cat_init(open_cat); open_cat->low = i + 1; open_cat->next = sl->cat; sl->cat = open_cat; } else { if (!open_cat) continue; open_cat->high = i; open_cat = NULL; } } if (open_cat) open_cat->high = i; return 0; } static int mls_range_to_semantic(mls_range_t * r, mls_semantic_range_t * sr) { if (mls_level_to_semantic(&r->level[0], &sr->level[0])) return -1; if (mls_level_to_semantic(&r->level[1], &sr->level[1])) return -1; return 0; } /* * Read and validate a security context structure * from a policydb binary representation file. */ static int context_read_and_validate(context_struct_t * c, policydb_t * p, struct policy_file *fp) { uint32_t buf[3]; int rc; rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) { ERR(fp->handle, "context truncated"); return -1; } c->user = le32_to_cpu(buf[0]); c->role = le32_to_cpu(buf[1]); c->type = le32_to_cpu(buf[2]); if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_MLS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_MLS)) { if (mls_read_range_helper(&c->range, fp)) { ERR(fp->handle, "error reading MLS range " "of context"); return -1; } } if (!policydb_context_isvalid(p, c)) { ERR(fp->handle, "invalid security context"); context_destroy(c); return -1; } return 0; } /* * The following *_read functions are used to * read the symbol data from a policy database * binary representation file. */ static int perm_read(policydb_t * p __attribute__ ((unused)), hashtab_t h, struct policy_file *fp) { char *key = 0; perm_datum_t *perdatum; uint32_t buf[2]; size_t len; int rc; perdatum = calloc(1, sizeof(perm_datum_t)); if (!perdatum) return -1; rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); perdatum->s.value = le32_to_cpu(buf[1]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (hashtab_insert(h, key, perdatum)) goto bad; return 0; bad: perm_destroy(key, perdatum, NULL); return -1; } static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp) { char *key = 0; common_datum_t *comdatum; uint32_t buf[4]; size_t len, nel; unsigned int i; int rc; comdatum = calloc(1, sizeof(common_datum_t)); if (!comdatum) return -1; rc = next_entry(buf, fp, sizeof(uint32_t) * 4); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); comdatum->s.value = le32_to_cpu(buf[1]); if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE)) goto bad; comdatum->permissions.nprim = le32_to_cpu(buf[2]); nel = le32_to_cpu(buf[3]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; for (i = 0; i < nel; i++) { if (perm_read(p, comdatum->permissions.table, fp)) goto bad; } if (hashtab_insert(h, key, comdatum)) goto bad; return 0; bad: common_destroy(key, comdatum, NULL); return -1; } static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep, unsigned int ncons, int allowxtarget, struct policy_file *fp) { constraint_node_t *c, *lc; constraint_expr_t *e, *le; uint32_t buf[3]; size_t nexpr; unsigned int i, j; int rc, depth; lc = NULL; for (i = 0; i < ncons; i++) { c = calloc(1, sizeof(constraint_node_t)); if (!c) return -1; if (lc) lc->next = c; else *nodep = c; rc = next_entry(buf, fp, (sizeof(uint32_t) * 2)); if (rc < 0) return -1; c->permissions = le32_to_cpu(buf[0]); nexpr = le32_to_cpu(buf[1]); le = NULL; depth = -1; for (j = 0; j < nexpr; j++) { e = malloc(sizeof(constraint_expr_t)); if (!e) return -1; if (constraint_expr_init(e) == -1) { free(e); return -1; } if (le) { le->next = e; } else { c->expr = e; } rc = next_entry(buf, fp, (sizeof(uint32_t) * 3)); if (rc < 0) return -1; e->expr_type = le32_to_cpu(buf[0]); e->attr = le32_to_cpu(buf[1]); e->op = le32_to_cpu(buf[2]); switch (e->expr_type) { case CEXPR_NOT: if (depth < 0) return -1; break; case CEXPR_AND: case CEXPR_OR: if (depth < 1) return -1; depth--; break; case CEXPR_ATTR: if (depth == (CEXPR_MAXDEPTH - 1)) return -1; depth++; break; case CEXPR_NAMES: if (!allowxtarget && (e->attr & CEXPR_XTARGET)) return -1; if (depth == (CEXPR_MAXDEPTH - 1)) return -1; depth++; if (ebitmap_read(&e->names, fp)) return -1; if (p->policy_type != POLICY_KERN && type_set_read(e->type_names, fp)) return -1; else if (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES && type_set_read(e->type_names, fp)) return -1; break; default: return -1; } le = e; } if (depth != 0) return -1; lc = c; } return 0; } static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp) { char *key = 0; class_datum_t *cladatum; uint32_t buf[6]; size_t len, len2, ncons, nel; unsigned int i; int rc; cladatum = (class_datum_t *) calloc(1, sizeof(class_datum_t)); if (!cladatum) return -1; rc = next_entry(buf, fp, sizeof(uint32_t) * 6); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); len2 = le32_to_cpu(buf[1]); cladatum->s.value = le32_to_cpu(buf[2]); if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE)) goto bad; cladatum->permissions.nprim = le32_to_cpu(buf[3]); nel = le32_to_cpu(buf[4]); ncons = le32_to_cpu(buf[5]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (len2) { cladatum->comkey = malloc(len2 + 1); if (!cladatum->comkey) goto bad; rc = next_entry(cladatum->comkey, fp, len2); if (rc < 0) goto bad; cladatum->comkey[len2] = 0; cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); if (!cladatum->comdatum) { ERR(fp->handle, "unknown common %s", cladatum->comkey); goto bad; } } for (i = 0; i < nel; i++) { if (perm_read(p, cladatum->permissions.table, fp)) goto bad; } if (read_cons_helper(p, &cladatum->constraints, ncons, 0, fp)) goto bad; if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) { /* grab the validatetrans rules */ rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; ncons = le32_to_cpu(buf[0]); if (read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp)) goto bad; } if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) { rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) goto bad; cladatum->default_user = le32_to_cpu(buf[0]); cladatum->default_role = le32_to_cpu(buf[1]); cladatum->default_range = le32_to_cpu(buf[2]); } if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; cladatum->default_type = le32_to_cpu(buf[0]); } if (hashtab_insert(h, key, cladatum)) goto bad; return 0; bad: class_destroy(key, cladatum, NULL); return -1; } static int role_read(policydb_t * p __attribute__ ((unused)), hashtab_t h, struct policy_file *fp) { char *key = 0; role_datum_t *role; uint32_t buf[3]; size_t len; int rc, to_read = 2; role = calloc(1, sizeof(role_datum_t)); if (!role) return -1; if (policydb_has_boundary_feature(p)) to_read = 3; rc = next_entry(buf, fp, sizeof(uint32_t) * to_read); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); role->s.value = le32_to_cpu(buf[1]); if (policydb_has_boundary_feature(p)) role->bounds = le32_to_cpu(buf[2]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (ebitmap_read(&role->dominates, fp)) goto bad; if (p->policy_type == POLICY_KERN) { if (ebitmap_read(&role->types.types, fp)) goto bad; } else { if (type_set_read(&role->types, fp)) goto bad; } if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; role->flavor = le32_to_cpu(buf[0]); if (ebitmap_read(&role->roles, fp)) goto bad; } if (strcmp(key, OBJECT_R) == 0) { if (role->s.value != OBJECT_R_VAL) { ERR(fp->handle, "role %s has wrong value %d", OBJECT_R, role->s.value); role_destroy(key, role, NULL); return -1; } role_destroy(key, role, NULL); return 0; } if (hashtab_insert(h, key, role)) goto bad; return 0; bad: role_destroy(key, role, NULL); return -1; } static int type_read(policydb_t * p __attribute__ ((unused)), hashtab_t h, struct policy_file *fp) { char *key = 0; type_datum_t *typdatum; uint32_t buf[5]; size_t len; int rc, to_read; int pos = 0; typdatum = calloc(1, sizeof(type_datum_t)); if (!typdatum) return -1; if (policydb_has_boundary_feature(p)) { if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) to_read = 5; else to_read = 4; } else if (p->policy_type == POLICY_KERN) to_read = 3; else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE) to_read = 5; else to_read = 4; rc = next_entry(buf, fp, sizeof(uint32_t) * to_read); if (rc < 0) goto bad; len = le32_to_cpu(buf[pos]); typdatum->s.value = le32_to_cpu(buf[++pos]); if (policydb_has_boundary_feature(p)) { uint32_t properties; if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) { typdatum->primary = le32_to_cpu(buf[++pos]); properties = le32_to_cpu(buf[++pos]); } else { properties = le32_to_cpu(buf[++pos]); if (properties & TYPEDATUM_PROPERTY_PRIMARY) typdatum->primary = 1; } if (properties & TYPEDATUM_PROPERTY_ATTRIBUTE) typdatum->flavor = TYPE_ATTRIB; if (properties & TYPEDATUM_PROPERTY_ALIAS && p->policy_type != POLICY_KERN) typdatum->flavor = TYPE_ALIAS; if (properties & TYPEDATUM_PROPERTY_PERMISSIVE && p->policy_type != POLICY_KERN) typdatum->flags |= TYPE_FLAGS_PERMISSIVE; typdatum->bounds = le32_to_cpu(buf[++pos]); } else { typdatum->primary = le32_to_cpu(buf[++pos]); if (p->policy_type != POLICY_KERN) { typdatum->flavor = le32_to_cpu(buf[++pos]); if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE) typdatum->flags = le32_to_cpu(buf[++pos]); } } if (p->policy_type != POLICY_KERN) { if (ebitmap_read(&typdatum->types, fp)) goto bad; } key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (hashtab_insert(h, key, typdatum)) goto bad; return 0; bad: type_destroy(key, typdatum, NULL); return -1; } int role_trans_read(policydb_t *p, struct policy_file *fp) { role_trans_t **t = &p->role_tr; unsigned int i; uint32_t buf[3], nel; role_trans_t *tr, *ltr; int rc; int new_roletr = (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_ROLETRANS); rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); ltr = NULL; for (i = 0; i < nel; i++) { tr = calloc(1, sizeof(struct role_trans)); if (!tr) { return -1; } if (ltr) { ltr->next = tr; } else { *t = tr; } rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) return -1; tr->role = le32_to_cpu(buf[0]); tr->type = le32_to_cpu(buf[1]); tr->new_role = le32_to_cpu(buf[2]); if (new_roletr) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; tr->tclass = le32_to_cpu(buf[0]); } else tr->tclass = SECCLASS_PROCESS; ltr = tr; } return 0; } int role_allow_read(role_allow_t ** r, struct policy_file *fp) { unsigned int i; uint32_t buf[2], nel; role_allow_t *ra, *lra; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); lra = NULL; for (i = 0; i < nel; i++) { ra = calloc(1, sizeof(struct role_allow)); if (!ra) { return -1; } if (lra) { lra->next = ra; } else { *r = ra; } rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; ra->role = le32_to_cpu(buf[0]); ra->new_role = le32_to_cpu(buf[1]); lra = ra; } return 0; } int filename_trans_read(filename_trans_t **t, struct policy_file *fp) { unsigned int i; uint32_t buf[4], nel, len; filename_trans_t *ft, *lft; int rc; char *name; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); lft = NULL; for (i = 0; i < nel; i++) { ft = calloc(1, sizeof(struct filename_trans)); if (!ft) return -1; if (lft) lft->next = ft; else *t = ft; lft = ft; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; len = le32_to_cpu(buf[0]); name = calloc(len + 1, sizeof(*name)); if (!name) return -1; ft->name = name; rc = next_entry(name, fp, len); if (rc < 0) return -1; rc = next_entry(buf, fp, sizeof(uint32_t) * 4); if (rc < 0) return -1; ft->stype = le32_to_cpu(buf[0]); ft->ttype = le32_to_cpu(buf[1]); ft->tclass = le32_to_cpu(buf[2]); ft->otype = le32_to_cpu(buf[3]); } return 0; } static int ocontext_read_xen(struct policydb_compat_info *info, policydb_t *p, struct policy_file *fp) { unsigned int i, j; size_t nel; ocontext_t *l, *c; uint32_t buf[8]; int rc; for (i = 0; i < info->ocon_num; i++) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); l = NULL; for (j = 0; j < nel; j++) { c = calloc(1, sizeof(ocontext_t)); if (!c) return -1; if (l) l->next = c; else p->ocontexts[i] = c; l = c; switch (i) { case OCON_XEN_ISID: rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; c->sid[0] = le32_to_cpu(buf[0]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_XEN_PIRQ: rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; c->u.pirq = le32_to_cpu(buf[0]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_XEN_IOPORT: rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; c->u.ioport.low_ioport = le32_to_cpu(buf[0]); c->u.ioport.high_ioport = le32_to_cpu(buf[1]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_XEN_IOMEM: rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; c->u.iomem.low_iomem = le32_to_cpu(buf[0]); c->u.iomem.high_iomem = le32_to_cpu(buf[1]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_XEN_PCIDEVICE: rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; c->u.device = le32_to_cpu(buf[0]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; default: /* should never get here */ ERR(fp->handle, "Unknown Xen ocontext"); return -1; } } } return 0; } static int ocontext_read_selinux(struct policydb_compat_info *info, policydb_t * p, struct policy_file *fp) { unsigned int i, j; size_t nel, len; ocontext_t *l, *c; uint32_t buf[8]; int rc; for (i = 0; i < info->ocon_num; i++) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); l = NULL; for (j = 0; j < nel; j++) { c = calloc(1, sizeof(ocontext_t)); if (!c) { return -1; } if (l) { l->next = c; } else { p->ocontexts[i] = c; } l = c; switch (i) { case OCON_ISID: rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; c->sid[0] = le32_to_cpu(buf[0]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_FS: case OCON_NETIF: rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; len = le32_to_cpu(buf[0]); c->u.name = malloc(len + 1); if (!c->u.name) return -1; rc = next_entry(c->u.name, fp, len); if (rc < 0) return -1; c->u.name[len] = 0; if (context_read_and_validate (&c->context[0], p, fp)) return -1; if (context_read_and_validate (&c->context[1], p, fp)) return -1; break; case OCON_PORT: rc = next_entry(buf, fp, sizeof(uint32_t) * 3); if (rc < 0) return -1; c->u.port.protocol = le32_to_cpu(buf[0]); c->u.port.low_port = le32_to_cpu(buf[1]); c->u.port.high_port = le32_to_cpu(buf[2]); if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_NODE: rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; c->u.node.addr = buf[0]; /* network order */ c->u.node.mask = buf[1]; /* network order */ if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_FSUSE: rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; c->v.behavior = le32_to_cpu(buf[0]); len = le32_to_cpu(buf[1]); c->u.name = malloc(len + 1); if (!c->u.name) return -1; rc = next_entry(c->u.name, fp, len); if (rc < 0) return -1; c->u.name[len] = 0; if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; case OCON_NODE6:{ int k; rc = next_entry(buf, fp, sizeof(uint32_t) * 8); if (rc < 0) return -1; for (k = 0; k < 4; k++) /* network order */ c->u.node6.addr[k] = buf[k]; for (k = 0; k < 4; k++) /* network order */ c->u.node6.mask[k] = buf[k + 4]; if (context_read_and_validate (&c->context[0], p, fp)) return -1; break; } default:{ ERR(fp->handle, "Unknown SELinux ocontext"); return -1; } } } } return 0; } static int ocontext_read(struct policydb_compat_info *info, policydb_t *p, struct policy_file *fp) { int rc = -1; switch (p->target_platform) { case SEPOL_TARGET_SELINUX: rc = ocontext_read_selinux(info, p, fp); break; case SEPOL_TARGET_XEN: rc = ocontext_read_xen(info, p, fp); break; default: ERR(fp->handle, "Unknown target"); } return rc; } static int genfs_read(policydb_t * p, struct policy_file *fp) { uint32_t buf[1]; size_t nel, nel2, len, len2; genfs_t *genfs_p, *newgenfs, *genfs; unsigned int i, j; ocontext_t *l, *c, *newc = NULL; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; nel = le32_to_cpu(buf[0]); genfs_p = NULL; for (i = 0; i < nel; i++) { rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); newgenfs = calloc(1, sizeof(genfs_t)); if (!newgenfs) goto bad; newgenfs->fstype = malloc(len + 1); if (!newgenfs->fstype) { free(newgenfs); goto bad; } rc = next_entry(newgenfs->fstype, fp, len); if (rc < 0) { free(newgenfs->fstype); free(newgenfs); goto bad; } newgenfs->fstype[len] = 0; for (genfs_p = NULL, genfs = p->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { if (strcmp(newgenfs->fstype, genfs->fstype) == 0) { ERR(fp->handle, "dup genfs fstype %s", newgenfs->fstype); free(newgenfs->fstype); free(newgenfs); goto bad; } if (strcmp(newgenfs->fstype, genfs->fstype) < 0) break; } newgenfs->next = genfs; if (genfs_p) genfs_p->next = newgenfs; else p->genfs = newgenfs; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; nel2 = le32_to_cpu(buf[0]); for (j = 0; j < nel2; j++) { newc = calloc(1, sizeof(ocontext_t)); if (!newc) { goto bad; } rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); newc->u.name = malloc(len + 1); if (!newc->u.name) { goto bad; } rc = next_entry(newc->u.name, fp, len); if (rc < 0) goto bad; newc->u.name[len] = 0; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; newc->v.sclass = le32_to_cpu(buf[0]); if (context_read_and_validate(&newc->context[0], p, fp)) goto bad; for (l = NULL, c = newgenfs->head; c; l = c, c = c->next) { if (!strcmp(newc->u.name, c->u.name) && (!c->v.sclass || !newc->v.sclass || newc->v.sclass == c->v.sclass)) { ERR(fp->handle, "dup genfs entry " "(%s,%s)", newgenfs->fstype, c->u.name); goto bad; } len = strlen(newc->u.name); len2 = strlen(c->u.name); if (len > len2) break; } newc->next = c; if (l) l->next = newc; else newgenfs->head = newc; } } return 0; bad: if (newc) { context_destroy(&newc->context[0]); context_destroy(&newc->context[1]); free(newc->u.name); free(newc); } return -1; } /* * Read a MLS level structure from a policydb binary * representation file. */ static int mls_read_level(mls_level_t * lp, struct policy_file *fp) { uint32_t buf[1]; int rc; mls_level_init(lp); rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { ERR(fp->handle, "truncated level"); goto bad; } lp->sens = le32_to_cpu(buf[0]); if (ebitmap_read(&lp->cat, fp)) { ERR(fp->handle, "error reading level categories"); goto bad; } return 0; bad: return -EINVAL; } static int user_read(policydb_t * p, hashtab_t h, struct policy_file *fp) { char *key = 0; user_datum_t *usrdatum; uint32_t buf[3]; size_t len; int rc, to_read = 2; usrdatum = calloc(1, sizeof(user_datum_t)); if (!usrdatum) return -1; if (policydb_has_boundary_feature(p)) to_read = 3; rc = next_entry(buf, fp, sizeof(uint32_t) * to_read); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); usrdatum->s.value = le32_to_cpu(buf[1]); if (policydb_has_boundary_feature(p)) usrdatum->bounds = le32_to_cpu(buf[2]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (p->policy_type == POLICY_KERN) { if (ebitmap_read(&usrdatum->roles.roles, fp)) goto bad; } else { if (role_set_read(&usrdatum->roles, fp)) goto bad; } /* users were not allowed in mls modules before version * MOD_POLICYDB_VERSION_MLS_USERS, but they could have been * required - the mls fields will be empty. user declarations in * non-mls modules will also have empty mls fields */ if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_MLS) || (p->policy_type == POLICY_MOD && p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS)) { if (mls_read_range_helper(&usrdatum->exp_range, fp)) goto bad; if (mls_read_level(&usrdatum->exp_dfltlevel, fp)) goto bad; if (p->policy_type != POLICY_KERN) { if (mls_range_to_semantic(&usrdatum->exp_range, &usrdatum->range)) goto bad; if (mls_level_to_semantic(&usrdatum->exp_dfltlevel, &usrdatum->dfltlevel)) goto bad; } } else if ((p->policy_type == POLICY_MOD && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS)) { if (mls_read_semantic_range_helper(&usrdatum->range, fp)) goto bad; if (mls_read_semantic_level_helper(&usrdatum->dfltlevel, fp)) goto bad; } if (hashtab_insert(h, key, usrdatum)) goto bad; return 0; bad: user_destroy(key, usrdatum, NULL); return -1; } static int sens_read(policydb_t * p __attribute__ ((unused)), hashtab_t h, struct policy_file *fp) { char *key = 0; level_datum_t *levdatum; uint32_t buf[2], len; int rc; levdatum = malloc(sizeof(level_datum_t)); if (!levdatum) return -1; level_datum_init(levdatum); rc = next_entry(buf, fp, (sizeof(uint32_t) * 2)); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); levdatum->isalias = le32_to_cpu(buf[1]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; levdatum->level = malloc(sizeof(mls_level_t)); if (!levdatum->level || mls_read_level(levdatum->level, fp)) goto bad; if (hashtab_insert(h, key, levdatum)) goto bad; return 0; bad: sens_destroy(key, levdatum, NULL); return -1; } static int cat_read(policydb_t * p __attribute__ ((unused)), hashtab_t h, struct policy_file *fp) { char *key = 0; cat_datum_t *catdatum; uint32_t buf[3], len; int rc; catdatum = malloc(sizeof(cat_datum_t)); if (!catdatum) return -1; cat_datum_init(catdatum); rc = next_entry(buf, fp, (sizeof(uint32_t) * 3)); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); catdatum->s.value = le32_to_cpu(buf[1]); catdatum->isalias = le32_to_cpu(buf[2]); key = malloc(len + 1); if (!key) goto bad; rc = next_entry(key, fp, len); if (rc < 0) goto bad; key[len] = 0; if (hashtab_insert(h, key, catdatum)) goto bad; return 0; bad: cat_destroy(key, catdatum, NULL); return -1; } static int (*read_f[SYM_NUM]) (policydb_t * p, hashtab_t h, struct policy_file * fp) = { common_read, class_read, role_read, type_read, user_read, cond_read_bool, sens_read, cat_read,}; /************** module reading functions below **************/ static avrule_t *avrule_read(policydb_t * p __attribute__ ((unused)), struct policy_file *fp) { unsigned int i; uint32_t buf[2], len; class_perm_node_t *cur, *tail = NULL; avrule_t *avrule; int rc; avrule = (avrule_t *) malloc(sizeof(avrule_t)); if (!avrule) return NULL; avrule_init(avrule); rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) goto bad; (avrule)->specified = le32_to_cpu(buf[0]); (avrule)->flags = le32_to_cpu(buf[1]); if (type_set_read(&avrule->stypes, fp)) goto bad; if (type_set_read(&avrule->ttypes, fp)) goto bad; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); for (i = 0; i < len; i++) { cur = (class_perm_node_t *) malloc(sizeof(class_perm_node_t)); if (!cur) goto bad; class_perm_node_init(cur); rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) { free(cur); goto bad; } cur->class = le32_to_cpu(buf[0]); cur->data = le32_to_cpu(buf[1]); if (!tail) { avrule->perms = cur; } else { tail->next = cur; } tail = cur; } return avrule; bad: if (avrule) { avrule_destroy(avrule); free(avrule); } return NULL; } static int range_read(policydb_t * p, struct policy_file *fp) { uint32_t buf[2], nel; range_trans_t *rt, *lrt; range_trans_rule_t *rtr, *lrtr = NULL; unsigned int i; int new_rangetr = (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_RANGETRANS); int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); lrt = NULL; for (i = 0; i < nel; i++) { rt = calloc(1, sizeof(range_trans_t)); if (!rt) return -1; if (lrt) lrt->next = rt; else p->range_tr = rt; rc = next_entry(buf, fp, (sizeof(uint32_t) * 2)); if (rc < 0) return -1; rt->source_type = le32_to_cpu(buf[0]); rt->target_type = le32_to_cpu(buf[1]); if (new_rangetr) { rc = next_entry(buf, fp, (sizeof(uint32_t))); if (rc < 0) return -1; rt->target_class = le32_to_cpu(buf[0]); } else rt->target_class = SECCLASS_PROCESS; if (mls_read_range_helper(&rt->target_range, fp)) return -1; lrt = rt; } /* if this is a kernel policy, we are done - otherwise we need to * convert these structs to range_trans_rule_ts */ if (p->policy_type == POLICY_KERN) return 0; /* create range_trans_rules_ts that correspond to the range_trans_ts * that were just read in from an older policy */ for (rt = p->range_tr; rt; rt = rt->next) { rtr = malloc(sizeof(range_trans_rule_t)); if (!rtr) { return -1; } range_trans_rule_init(rtr); if (lrtr) lrtr->next = rtr; else p->global->enabled->range_tr_rules = rtr; if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1)) return -1; if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1)) return -1; if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1)) return -1; if (mls_range_to_semantic(&rt->target_range, &rtr->trange)) return -1; lrtr = rtr; } /* now destroy the range_trans_ts */ lrt = NULL; for (rt = p->range_tr; rt; rt = rt->next) { if (lrt) { ebitmap_destroy(&lrt->target_range.level[0].cat); ebitmap_destroy(&lrt->target_range.level[1].cat); free(lrt); } lrt = rt; } if (lrt) { ebitmap_destroy(&lrt->target_range.level[0].cat); ebitmap_destroy(&lrt->target_range.level[1].cat); free(lrt); } p->range_tr = NULL; return 0; } int avrule_read_list(policydb_t * p, avrule_t ** avrules, struct policy_file *fp) { unsigned int i; avrule_t *cur, *tail; uint32_t buf[1], len; int rc; *avrules = tail = NULL; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { return -1; } len = le32_to_cpu(buf[0]); for (i = 0; i < len; i++) { cur = avrule_read(p, fp); if (!cur) { return -1; } if (!tail) { *avrules = cur; } else { tail->next = cur; } tail = cur; } return 0; } static int role_trans_rule_read(policydb_t *p, role_trans_rule_t ** r, struct policy_file *fp) { uint32_t buf[1], nel; unsigned int i; role_trans_rule_t *tr, *ltr; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); ltr = NULL; for (i = 0; i < nel; i++) { tr = malloc(sizeof(role_trans_rule_t)); if (!tr) { return -1; } role_trans_rule_init(tr); if (ltr) { ltr->next = tr; } else { *r = tr; } if (role_set_read(&tr->roles, fp)) return -1; if (type_set_read(&tr->types, fp)) return -1; if (p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS) { if (ebitmap_read(&tr->classes, fp)) return -1; } else { if (ebitmap_set_bit(&tr->classes, SECCLASS_PROCESS - 1, 1)) return -1; } rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; tr->new_role = le32_to_cpu(buf[0]); ltr = tr; } return 0; } static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp) { unsigned int i; uint32_t buf[1], nel; role_allow_rule_t *ra, *lra; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); lra = NULL; for (i = 0; i < nel; i++) { ra = malloc(sizeof(role_allow_rule_t)); if (!ra) { return -1; } role_allow_rule_init(ra); if (lra) { lra->next = ra; } else { *r = ra; } if (role_set_read(&ra->roles, fp)) return -1; if (role_set_read(&ra->new_roles, fp)) return -1; lra = ra; } return 0; } static int filename_trans_rule_read(filename_trans_rule_t ** r, struct policy_file *fp) { uint32_t buf[2], nel; unsigned int i, len; filename_trans_rule_t *ftr, *lftr; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); lftr = NULL; for (i = 0; i < nel; i++) { ftr = malloc(sizeof(*ftr)); if (!ftr) return -1; filename_trans_rule_init(ftr); if (lftr) lftr->next = ftr; else *r = ftr; lftr = ftr; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; len = le32_to_cpu(buf[0]); ftr->name = malloc(len + 1); if (!ftr->name) return -1; rc = next_entry(ftr->name, fp, len); if (rc) return -1; ftr->name[len] = 0; if (type_set_read(&ftr->stypes, fp)) return -1; if (type_set_read(&ftr->ttypes, fp)) return -1; rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; ftr->tclass = le32_to_cpu(buf[0]); ftr->otype = le32_to_cpu(buf[1]); } return 0; } static int range_trans_rule_read(range_trans_rule_t ** r, struct policy_file *fp) { uint32_t buf[1], nel; unsigned int i; range_trans_rule_t *rt, *lrt = NULL; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); for (i = 0; i < nel; i++) { rt = malloc(sizeof(range_trans_rule_t)); if (!rt) { return -1; } range_trans_rule_init(rt); if (lrt) lrt->next = rt; else *r = rt; if (type_set_read(&rt->stypes, fp)) return -1; if (type_set_read(&rt->ttypes, fp)) return -1; if (ebitmap_read(&rt->tclasses, fp)) return -1; if (mls_read_semantic_range_helper(&rt->trange, fp)) return -1; lrt = rt; } return 0; } static int scope_index_read(scope_index_t * scope_index, unsigned int num_scope_syms, struct policy_file *fp) { unsigned int i; uint32_t buf[1]; int rc; for (i = 0; i < num_scope_syms; i++) { if (ebitmap_read(scope_index->scope + i, fp) == -1) { return -1; } } rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; scope_index->class_perms_len = le32_to_cpu(buf[0]); if (scope_index->class_perms_len == 0) { scope_index->class_perms_map = NULL; return 0; } if ((scope_index->class_perms_map = calloc(scope_index->class_perms_len, sizeof(*scope_index->class_perms_map))) == NULL) { return -1; } for (i = 0; i < scope_index->class_perms_len; i++) { if (ebitmap_read(scope_index->class_perms_map + i, fp) == -1) { return -1; } } return 0; } static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl, unsigned int num_scope_syms, struct policy_file *fp) { uint32_t buf[2], nprim, nel; unsigned int i, j; int rc; rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; decl->decl_id = le32_to_cpu(buf[0]); decl->enabled = le32_to_cpu(buf[1]); if (cond_read_list(p, &decl->cond_list, fp) == -1 || avrule_read_list(p, &decl->avrules, fp) == -1 || role_trans_rule_read(p, &decl->role_tr_rules, fp) == -1 || role_allow_rule_read(&decl->role_allow_rules, fp) == -1) { return -1; } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && filename_trans_rule_read(&decl->filename_trans_rules, fp)) return -1; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && range_trans_rule_read(&decl->range_tr_rules, fp) == -1) { return -1; } if (scope_index_read(&decl->required, num_scope_syms, fp) == -1 || scope_index_read(&decl->declared, num_scope_syms, fp) == -1) { return -1; } for (i = 0; i < num_scope_syms; i++) { rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return -1; nprim = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[1]); for (j = 0; j < nel; j++) { if (read_f[i] (p, decl->symtab[i].table, fp)) { return -1; } } decl->symtab[i].nprim = nprim; } return 0; } static int avrule_block_read(policydb_t * p, avrule_block_t ** block, unsigned int num_scope_syms, struct policy_file *fp) { avrule_block_t *last_block = NULL, *curblock; uint32_t buf[1], num_blocks, nel; int rc; assert(*block == NULL); rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; num_blocks = le32_to_cpu(buf[0]); nel = num_blocks; while (num_blocks > 0) { avrule_decl_t *last_decl = NULL, *curdecl; uint32_t num_decls; if ((curblock = calloc(1, sizeof(*curblock))) == NULL) { return -1; } rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) { free(curblock); return -1; } /* if this is the first block its non-optional, else its optional */ if (num_blocks != nel) curblock->flags |= AVRULE_OPTIONAL; num_decls = le32_to_cpu(buf[0]); while (num_decls > 0) { if ((curdecl = avrule_decl_create(0)) == NULL) { avrule_block_destroy(curblock); return -1; } if (avrule_decl_read(p, curdecl, num_scope_syms, fp) == -1) { avrule_decl_destroy(curdecl); avrule_block_destroy(curblock); return -1; } if (curdecl->enabled) { if (curblock->enabled != NULL) { /* probably a corrupt file */ avrule_decl_destroy(curdecl); avrule_block_destroy(curblock); return -1; } curblock->enabled = curdecl; } /* one must be careful to reconstruct the * decl chain in its correct order */ if (curblock->branch_list == NULL) { curblock->branch_list = curdecl; } else { assert(last_decl); last_decl->next = curdecl; } last_decl = curdecl; num_decls--; } if (*block == NULL) { *block = curblock; } else { assert(last_block); last_block->next = curblock; } last_block = curblock; num_blocks--; } return 0; } static int scope_read(policydb_t * p, int symnum, struct policy_file *fp) { scope_datum_t *scope = NULL; uint32_t buf[2]; char *key = NULL; size_t key_len; unsigned int i; hashtab_t h = p->scope[symnum].table; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) goto cleanup; key_len = le32_to_cpu(buf[0]); key = malloc(key_len + 1); if (!key) goto cleanup; rc = next_entry(key, fp, key_len); if (rc < 0) goto cleanup; key[key_len] = '\0'; /* ensure that there already exists a symbol with this key */ if (hashtab_search(p->symtab[symnum].table, key) == NULL) { goto cleanup; } if ((scope = calloc(1, sizeof(*scope))) == NULL) { goto cleanup; } rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) goto cleanup; scope->scope = le32_to_cpu(buf[0]); scope->decl_ids_len = le32_to_cpu(buf[1]); assert(scope->decl_ids_len > 0); if ((scope->decl_ids = malloc(scope->decl_ids_len * sizeof(uint32_t))) == NULL) { goto cleanup; } rc = next_entry(scope->decl_ids, fp, sizeof(uint32_t) * scope->decl_ids_len); if (rc < 0) goto cleanup; for (i = 0; i < scope->decl_ids_len; i++) { scope->decl_ids[i] = le32_to_cpu(scope->decl_ids[i]); } if (strcmp(key, "object_r") == 0 && h == p->p_roles_scope.table) { /* object_r was already added to this table in roles_init() */ scope_destroy(key, scope, NULL); } else { if (hashtab_insert(h, key, scope)) { goto cleanup; } } return 0; cleanup: scope_destroy(key, scope, NULL); return -1; } /* * Read the configuration data from a policy database binary * representation file into a policy database structure. */ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) { unsigned int i, j, r_policyvers; uint32_t buf[5]; size_t len, nprim, nel; char *policydb_str; struct policydb_compat_info *info; unsigned int policy_type, bufindex; ebitmap_node_t *tnode; int rc; /* Read the magic number and string length. */ rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) return POLICYDB_ERROR; for (i = 0; i < 2; i++) buf[i] = le32_to_cpu(buf[i]); if (buf[0] == POLICYDB_MAGIC) { policy_type = POLICY_KERN; } else if (buf[0] == POLICYDB_MOD_MAGIC) { policy_type = POLICY_MOD; } else { ERR(fp->handle, "policydb magic number %#08x does not " "match expected magic number %#08x or %#08x", buf[0], POLICYDB_MAGIC, POLICYDB_MOD_MAGIC); return POLICYDB_ERROR; } len = buf[1]; if (len > POLICYDB_STRING_MAX_LENGTH) { ERR(fp->handle, "policydb string length too long "); return POLICYDB_ERROR; } policydb_str = malloc(len + 1); if (!policydb_str) { ERR(fp->handle, "unable to allocate memory for policydb " "string of length %zu", len); return POLICYDB_ERROR; } rc = next_entry(policydb_str, fp, len); if (rc < 0) { ERR(fp->handle, "truncated policydb string identifier"); free(policydb_str); return POLICYDB_ERROR; } policydb_str[len] = 0; if (policy_type == POLICY_KERN) { for (i = 0; i < POLICYDB_TARGET_SZ; i++) { if ((strcmp(policydb_str, policydb_target_strings[i]) == 0)) { policydb_set_target_platform(p, i); break; } } if (i == POLICYDB_TARGET_SZ) { ERR(fp->handle, "cannot find a valid target for policy " "string %s", policydb_str); free(policydb_str); return POLICYDB_ERROR; } } else { if (strcmp(policydb_str, POLICYDB_MOD_STRING)) { ERR(fp->handle, "invalid string identifier %s", policydb_str); free(policydb_str); return POLICYDB_ERROR; } } /* Done with policydb_str. */ free(policydb_str); policydb_str = NULL; /* Read the version, config, and table sizes (and policy type if it's a module). */ if (policy_type == POLICY_KERN) nel = 4; else nel = 5; rc = next_entry(buf, fp, sizeof(uint32_t) * nel); if (rc < 0) return POLICYDB_ERROR; for (i = 0; i < nel; i++) buf[i] = le32_to_cpu(buf[i]); bufindex = 0; if (policy_type == POLICY_MOD) { /* We know it's a module but not whether it's a base module or regular binary policy module. buf[0] tells us which. */ policy_type = buf[bufindex]; if (policy_type != POLICY_MOD && policy_type != POLICY_BASE) { ERR(fp->handle, "unknown module type: %#08x", policy_type); return POLICYDB_ERROR; } bufindex++; } r_policyvers = buf[bufindex]; if (policy_type == POLICY_KERN) { if (r_policyvers < POLICYDB_VERSION_MIN || r_policyvers > POLICYDB_VERSION_MAX) { ERR(fp->handle, "policydb version %d does not match " "my version range %d-%d", buf[bufindex], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); return POLICYDB_ERROR; } } else if (policy_type == POLICY_BASE || policy_type == POLICY_MOD) { if (r_policyvers < MOD_POLICYDB_VERSION_MIN || r_policyvers > MOD_POLICYDB_VERSION_MAX) { ERR(fp->handle, "policydb module version %d does " "not match my version range %d-%d", buf[bufindex], MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX); return POLICYDB_ERROR; } } else { assert(0); } bufindex++; /* Set the policy type and version from the read values. */ p->policy_type = policy_type; p->policyvers = r_policyvers; if (buf[bufindex] & POLICYDB_CONFIG_MLS) { p->mls = 1; } else { p->mls = 0; } p->handle_unknown = buf[bufindex] & POLICYDB_CONFIG_UNKNOWN_MASK; bufindex++; info = policydb_lookup_compat(r_policyvers, policy_type, p->target_platform); if (!info) { ERR(fp->handle, "unable to find policy compat info " "for version %d", r_policyvers); goto bad; } if (buf[bufindex] != info->sym_num || buf[bufindex + 1] != info->ocon_num) { ERR(fp->handle, "policydb table sizes (%d,%d) do not " "match mine (%d,%d)", buf[bufindex], buf[bufindex + 1], info->sym_num, info->ocon_num); goto bad; } if (p->policy_type == POLICY_MOD) { /* Get the module name and version */ if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) { goto bad; } len = le32_to_cpu(buf[0]); if ((p->name = malloc(len + 1)) == NULL) { goto bad; } if ((rc = next_entry(p->name, fp, len)) < 0) { goto bad; } p->name[len] = '\0'; if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) { goto bad; } len = le32_to_cpu(buf[0]); if ((p->version = malloc(len + 1)) == NULL) { goto bad; } if ((rc = next_entry(p->version, fp, len)) < 0) { goto bad; } p->version[len] = '\0'; } if ((p->policyvers >= POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_KERN) || (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_BASE) || (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_MOD)) { if (ebitmap_read(&p->policycaps, fp)) goto bad; } if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && p->policy_type == POLICY_KERN) { if (ebitmap_read(&p->permissive_map, fp)) goto bad; } for (i = 0; i < info->sym_num; i++) { rc = next_entry(buf, fp, sizeof(uint32_t) * 2); if (rc < 0) goto bad; nprim = le32_to_cpu(buf[0]); nel = le32_to_cpu(buf[1]); for (j = 0; j < nel; j++) { if (read_f[i] (p, p->symtab[i].table, fp)) goto bad; } p->symtab[i].nprim = nprim; } if (policy_type == POLICY_KERN) { if (avtab_read(&p->te_avtab, fp, r_policyvers)) goto bad; if (r_policyvers >= POLICYDB_VERSION_BOOL) if (cond_read_list(p, &p->cond_list, fp)) goto bad; if (role_trans_read(p, fp)) goto bad; if (role_allow_read(&p->role_allow, fp)) goto bad; if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS && filename_trans_read(&p->filename_trans, fp)) goto bad; } else { /* first read the AV rule blocks, then the scope tables */ avrule_block_destroy(p->global); p->global = NULL; if (avrule_block_read(p, &p->global, info->sym_num, fp) == -1) { goto bad; } for (i = 0; i < info->sym_num; i++) { if ((rc = next_entry(buf, fp, sizeof(uint32_t))) < 0) { goto bad; } nel = le32_to_cpu(buf[0]); for (j = 0; j < nel; j++) { if (scope_read(p, i, fp)) goto bad; } } } if (policydb_index_decls(p)) goto bad; if (policydb_index_classes(p)) goto bad; if (policydb_index_others(fp->handle, p, verbose)) goto bad; if (ocontext_read(info, p, fp) == -1) { goto bad; } if (genfs_read(p, fp) == -1) { goto bad; } if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_MLS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS)) { if (range_read(p, fp)) { goto bad; } } if (policy_type == POLICY_KERN) { p->type_attr_map = malloc(p->p_types.nprim * sizeof(ebitmap_t)); p->attr_type_map = malloc(p->p_types.nprim * sizeof(ebitmap_t)); if (!p->type_attr_map || !p->attr_type_map) goto bad; for (i = 0; i < p->p_types.nprim; i++) { ebitmap_init(&p->type_attr_map[i]); ebitmap_init(&p->attr_type_map[i]); } for (i = 0; i < p->p_types.nprim; i++) { if (r_policyvers >= POLICYDB_VERSION_AVTAB) { if (ebitmap_read(&p->type_attr_map[i], fp)) goto bad; ebitmap_for_each_bit(&p->type_attr_map[i], tnode, j) { if (!ebitmap_node_get_bit(tnode, j) || i == j) continue; if (ebitmap_set_bit (&p->attr_type_map[j], i, 1)) goto bad; } } /* add the type itself as the degenerate case */ if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) goto bad; } } return POLICYDB_SUCCESS; bad: return POLICYDB_ERROR; } int policydb_reindex_users(policydb_t * p) { unsigned int i = SYM_USERS; if (p->user_val_to_struct) free(p->user_val_to_struct); if (p->sym_val_to_name[i]) free(p->sym_val_to_name[i]); p->user_val_to_struct = (user_datum_t **) malloc(p->p_users.nprim * sizeof(user_datum_t *)); if (!p->user_val_to_struct) return -1; p->sym_val_to_name[i] = (char **) malloc(p->symtab[i].nprim * sizeof(char *)); if (!p->sym_val_to_name[i]) return -1; if (hashtab_map(p->symtab[i].table, index_f[i], p)) return -1; /* Expand user roles for context validity checking */ if (hashtab_map(p->p_users.table, policydb_user_cache, p)) return -1; return 0; } void policy_file_init(policy_file_t *pf) { memset(pf, 0, sizeof(policy_file_t)); } int policydb_set_target_platform(policydb_t *p, int platform) { if (platform == SEPOL_TARGET_SELINUX) p->target_platform = SEPOL_TARGET_SELINUX; else if (platform == SEPOL_TARGET_XEN) p->target_platform = SEPOL_TARGET_XEN; else return -1; return 0; } libsepol-2.2/src/policydb_convert.c000066400000000000000000000040721223423440700174720ustar00rootroot00000000000000#include #include "private.h" #include "debug.h" #include /* Construct a policydb from the supplied (data, len) pair */ int policydb_from_image(sepol_handle_t * handle, void *data, size_t len, policydb_t * policydb) { policy_file_t pf; policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = data; pf.len = len; pf.handle = handle; if (policydb_read(policydb, &pf, 0)) { policydb_destroy(policydb); ERR(handle, "policy image is invalid"); errno = EINVAL; return STATUS_ERR; } return STATUS_SUCCESS; } /* Write a policydb to a memory region, and return the (data, len) pair. */ int policydb_to_image(sepol_handle_t * handle, policydb_t * policydb, void **newdata, size_t * newlen) { void *tmp_data = NULL; size_t tmp_len; policy_file_t pf; struct policydb tmp_policydb; /* Compute the length for the new policy image. */ policy_file_init(&pf); pf.type = PF_LEN; pf.handle = handle; if (policydb_write(policydb, &pf)) { ERR(handle, "could not compute policy length"); errno = EINVAL; goto err; } /* Allocate the new policy image. */ pf.type = PF_USE_MEMORY; pf.data = malloc(pf.len); if (!pf.data) { ERR(handle, "out of memory"); goto err; } /* Need to save len and data prior to modification by policydb_write. */ tmp_len = pf.len; tmp_data = pf.data; /* Write out the new policy image. */ if (policydb_write(policydb, &pf)) { ERR(handle, "could not write policy"); errno = EINVAL; goto err; } /* Verify the new policy image. */ pf.type = PF_USE_MEMORY; pf.data = tmp_data; pf.len = tmp_len; if (policydb_init(&tmp_policydb)) { ERR(handle, "Out of memory"); errno = ENOMEM; goto err; } if (policydb_read(&tmp_policydb, &pf, 0)) { ERR(handle, "new policy image is invalid"); errno = EINVAL; goto err; } policydb_destroy(&tmp_policydb); /* Update (newdata, newlen) */ *newdata = tmp_data; *newlen = tmp_len; /* Recover */ return STATUS_SUCCESS; err: ERR(handle, "could not create policy image"); /* Recover */ free(tmp_data); return STATUS_ERR; } libsepol-2.2/src/policydb_internal.h000066400000000000000000000003601223423440700176270ustar00rootroot00000000000000#ifndef _SEPOL_POLICYDB_INTERNAL_H_ #define _SEPOL_POLICYDB_INTERNAL_H_ #include #include "dso.h" hidden_proto(sepol_policydb_create) hidden_proto(sepol_policydb_free) extern char *policydb_target_strings[]; #endif libsepol-2.2/src/policydb_public.c000066400000000000000000000072201223423440700172660ustar00rootroot00000000000000#include #include "debug.h" #include #include "policydb_internal.h" /* Policy file interfaces. */ int sepol_policy_file_create(sepol_policy_file_t ** pf) { *pf = calloc(1, sizeof(sepol_policy_file_t)); if (!(*pf)) return -1; return 0; } void sepol_policy_file_set_mem(sepol_policy_file_t * spf, char *data, size_t len) { struct policy_file *pf = &spf->pf; if (!len) { pf->type = PF_LEN; return; } pf->type = PF_USE_MEMORY; pf->data = data; pf->len = len; pf->size = len; return; } void sepol_policy_file_set_fp(sepol_policy_file_t * spf, FILE * fp) { struct policy_file *pf = &spf->pf; pf->type = PF_USE_STDIO; pf->fp = fp; return; } int sepol_policy_file_get_len(sepol_policy_file_t * spf, size_t * len) { struct policy_file *pf = &spf->pf; if (pf->type != PF_LEN) return -1; *len = pf->len; return 0; } void sepol_policy_file_set_handle(sepol_policy_file_t * pf, sepol_handle_t * handle) { pf->pf.handle = handle; } void sepol_policy_file_free(sepol_policy_file_t * pf) { free(pf); } /* Policydb interfaces. */ int sepol_policydb_create(sepol_policydb_t ** sp) { policydb_t *p; *sp = malloc(sizeof(sepol_policydb_t)); if (!(*sp)) return -1; p = &(*sp)->p; if (policydb_init(p)) { free(*sp); return -1; } return 0; } hidden_def(sepol_policydb_create) void sepol_policydb_free(sepol_policydb_t * p) { if (!p) return; policydb_destroy(&p->p); free(p); } hidden_def(sepol_policydb_free) int sepol_policy_kern_vers_min(void) { return POLICYDB_VERSION_MIN; } int sepol_policy_kern_vers_max(void) { return POLICYDB_VERSION_MAX; } int sepol_policydb_set_typevers(sepol_policydb_t * sp, unsigned int type) { struct policydb *p = &sp->p; switch (type) { case POLICY_KERN: p->policyvers = POLICYDB_VERSION_MAX; break; case POLICY_BASE: case POLICY_MOD: p->policyvers = MOD_POLICYDB_VERSION_MAX; break; default: return -1; } p->policy_type = type; return 0; } int sepol_policydb_set_vers(sepol_policydb_t * sp, unsigned int vers) { struct policydb *p = &sp->p; switch (p->policy_type) { case POLICY_KERN: if (vers < POLICYDB_VERSION_MIN || vers > POLICYDB_VERSION_MAX) return -1; break; case POLICY_BASE: case POLICY_MOD: if (vers < MOD_POLICYDB_VERSION_MIN || vers > MOD_POLICYDB_VERSION_MAX) return -1; break; default: return -1; } p->policyvers = vers; return 0; } int sepol_policydb_set_handle_unknown(sepol_policydb_t * sp, unsigned int handle_unknown) { struct policydb *p = &sp->p; switch (handle_unknown) { case SEPOL_DENY_UNKNOWN: case SEPOL_REJECT_UNKNOWN: case SEPOL_ALLOW_UNKNOWN: break; default: return -1; } p->handle_unknown = handle_unknown; return 0; } int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf) { return policydb_read(&p->p, &pf->pf, 0); } int sepol_policydb_write(sepol_policydb_t * p, sepol_policy_file_t * pf) { return policydb_write(&p->p, &pf->pf); } int sepol_policydb_from_image(sepol_handle_t * handle, void *data, size_t len, sepol_policydb_t * p) { return policydb_from_image(handle, data, len, &p->p); } int sepol_policydb_to_image(sepol_handle_t * handle, sepol_policydb_t * p, void **newdata, size_t * newlen) { return policydb_to_image(handle, &p->p, newdata, newlen); } int sepol_policydb_mls_enabled(const sepol_policydb_t * p) { return p->p.mls; } /* * Enable compatibility mode for SELinux network checks iff * the packet class is not defined in the policy. */ #define PACKET_CLASS_NAME "packet" int sepol_policydb_compat_net(const sepol_policydb_t * p) { return (hashtab_search(p->p.p_classes.table, PACKET_CLASS_NAME) == NULL); } libsepol-2.2/src/port_internal.h000066400000000000000000000011311223423440700170030ustar00rootroot00000000000000#ifndef _SEPOL_PORT_INTERNAL_H_ #define _SEPOL_PORT_INTERNAL_H_ #include #include #include "dso.h" hidden_proto(sepol_port_create) hidden_proto(sepol_port_free) hidden_proto(sepol_port_get_con) hidden_proto(sepol_port_get_high) hidden_proto(sepol_port_get_low) hidden_proto(sepol_port_get_proto) hidden_proto(sepol_port_get_proto_str) hidden_proto(sepol_port_key_create) hidden_proto(sepol_port_key_unpack) hidden_proto(sepol_port_set_con) hidden_proto(sepol_port_set_proto) hidden_proto(sepol_port_set_range) #endif libsepol-2.2/src/port_record.c000066400000000000000000000117261223423440700164530ustar00rootroot00000000000000#include #include #include "port_internal.h" #include "context_internal.h" #include "debug.h" struct sepol_port { /* Low - High range. Same for single ports. */ int low, high; /* Protocol */ int proto; /* Context */ sepol_context_t *con; }; struct sepol_port_key { /* Low - High range. Same for single ports. */ int low, high; /* Protocol */ int proto; }; /* Key */ int sepol_port_key_create(sepol_handle_t * handle, int low, int high, int proto, sepol_port_key_t ** key_ptr) { sepol_port_key_t *tmp_key = (sepol_port_key_t *) malloc(sizeof(sepol_port_key_t)); if (!tmp_key) { ERR(handle, "out of memory, could not create " "port key"); return STATUS_ERR; } tmp_key->low = low; tmp_key->high = high; tmp_key->proto = proto; *key_ptr = tmp_key; return STATUS_SUCCESS; } hidden_def(sepol_port_key_create) void sepol_port_key_unpack(const sepol_port_key_t * key, int *low, int *high, int *proto) { *low = key->low; *high = key->high; *proto = key->proto; } hidden_def(sepol_port_key_unpack) int sepol_port_key_extract(sepol_handle_t * handle, const sepol_port_t * port, sepol_port_key_t ** key_ptr) { if (sepol_port_key_create (handle, port->low, port->high, port->proto, key_ptr) < 0) { ERR(handle, "could not extract key from port %s %d:%d", sepol_port_get_proto_str(port->proto), port->low, port->high); return STATUS_ERR; } return STATUS_SUCCESS; } void sepol_port_key_free(sepol_port_key_t * key) { free(key); } int sepol_port_compare(const sepol_port_t * port, const sepol_port_key_t * key) { if ((port->low == key->low) && (port->high == key->high) && (port->proto == key->proto)) return 0; if (port->low < key->low) return -1; else if (key->low < port->low) return 1; else if (port->high < key->high) return -1; else if (key->high < port->high) return 1; else if (port->proto < key->proto) return -1; else return 1; } int sepol_port_compare2(const sepol_port_t * port, const sepol_port_t * port2) { if ((port->low == port2->low) && (port->high == port2->high) && (port->proto == port2->proto)) return 0; if (port->low < port2->low) return -1; else if (port2->low < port->low) return 1; else if (port->high < port2->high) return -1; else if (port2->high < port->high) return 1; else if (port->proto < port2->proto) return -1; else return 1; } /* Port */ int sepol_port_get_low(const sepol_port_t * port) { return port->low; } hidden_def(sepol_port_get_low) int sepol_port_get_high(const sepol_port_t * port) { return port->high; } hidden_def(sepol_port_get_high) void sepol_port_set_port(sepol_port_t * port, int port_num) { port->low = port_num; port->high = port_num; } void sepol_port_set_range(sepol_port_t * port, int low, int high) { port->low = low; port->high = high; } hidden_def(sepol_port_set_range) /* Protocol */ int sepol_port_get_proto(const sepol_port_t * port) { return port->proto; } hidden_def(sepol_port_get_proto) const char *sepol_port_get_proto_str(int proto) { switch (proto) { case SEPOL_PROTO_UDP: return "udp"; case SEPOL_PROTO_TCP: return "tcp"; default: return "???"; } } hidden_def(sepol_port_get_proto_str) void sepol_port_set_proto(sepol_port_t * port, int proto) { port->proto = proto; } hidden_def(sepol_port_set_proto) /* Create */ int sepol_port_create(sepol_handle_t * handle, sepol_port_t ** port) { sepol_port_t *tmp_port = (sepol_port_t *) malloc(sizeof(sepol_port_t)); if (!tmp_port) { ERR(handle, "out of memory, could not create " "port record"); return STATUS_ERR; } tmp_port->low = 0; tmp_port->high = 0; tmp_port->proto = SEPOL_PROTO_UDP; tmp_port->con = NULL; *port = tmp_port; return STATUS_SUCCESS; } hidden_def(sepol_port_create) /* Deep copy clone */ int sepol_port_clone(sepol_handle_t * handle, const sepol_port_t * port, sepol_port_t ** port_ptr) { sepol_port_t *new_port = NULL; if (sepol_port_create(handle, &new_port) < 0) goto err; new_port->low = port->low; new_port->high = port->high; new_port->proto = port->proto; if (port->con && (sepol_context_clone(handle, port->con, &new_port->con) < 0)) goto err; *port_ptr = new_port; return STATUS_SUCCESS; err: ERR(handle, "could not clone port record"); sepol_port_free(new_port); return STATUS_ERR; } /* Destroy */ void sepol_port_free(sepol_port_t * port) { if (!port) return; sepol_context_free(port->con); free(port); } hidden_def(sepol_port_free) /* Context */ sepol_context_t *sepol_port_get_con(const sepol_port_t * port) { return port->con; } hidden_def(sepol_port_get_con) int sepol_port_set_con(sepol_handle_t * handle, sepol_port_t * port, sepol_context_t * con) { sepol_context_t *newcon; if (sepol_context_clone(handle, con, &newcon) < 0) { ERR(handle, "out of memory, could not set port context"); return STATUS_ERR; } sepol_context_free(port->con); port->con = newcon; return STATUS_SUCCESS; } hidden_def(sepol_port_set_con) libsepol-2.2/src/ports.c000066400000000000000000000157171223423440700153040ustar00rootroot00000000000000#include #include #include "debug.h" #include "context.h" #include "handle.h" #include #include "port_internal.h" static inline int sepol2ipproto(sepol_handle_t * handle, int proto) { switch (proto) { case SEPOL_PROTO_TCP: return IPPROTO_TCP; case SEPOL_PROTO_UDP: return IPPROTO_UDP; default: ERR(handle, "unsupported protocol %u", proto); return STATUS_ERR; } } static inline int ipproto2sepol(sepol_handle_t * handle, int proto) { switch (proto) { case IPPROTO_TCP: return SEPOL_PROTO_TCP; case IPPROTO_UDP: return SEPOL_PROTO_UDP; default: ERR(handle, "invalid protocol %u " "found in policy", proto); return STATUS_ERR; } } /* Create a low level port structure from * a high level representation */ static int port_from_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t ** port, const sepol_port_t * data) { ocontext_t *tmp_port = NULL; context_struct_t *tmp_con = NULL; int tmp_proto; int low = sepol_port_get_low(data); int high = sepol_port_get_high(data); int proto = sepol_port_get_proto(data); tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t)); if (!tmp_port) goto omem; /* Process protocol */ tmp_proto = sepol2ipproto(handle, proto); if (tmp_proto < 0) goto err; tmp_port->u.port.protocol = tmp_proto; /* Port range */ tmp_port->u.port.low_port = low; tmp_port->u.port.high_port = high; if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) { ERR(handle, "low port %d exceeds high port %d", tmp_port->u.port.low_port, tmp_port->u.port.high_port); goto err; } /* Context */ if (context_from_record(handle, policydb, &tmp_con, sepol_port_get_con(data)) < 0) goto err; context_cpy(&tmp_port->context[0], tmp_con); context_destroy(tmp_con); free(tmp_con); tmp_con = NULL; *port = tmp_port; return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: if (tmp_port != NULL) { context_destroy(&tmp_port->context[0]); free(tmp_port); } context_destroy(tmp_con); free(tmp_con); ERR(handle, "could not create port structure for range %u:%u (%s)", low, high, sepol_port_get_proto_str(proto)); return STATUS_ERR; } static int port_to_record(sepol_handle_t * handle, const policydb_t * policydb, ocontext_t * port, sepol_port_t ** record) { int proto = port->u.port.protocol; int low = port->u.port.low_port; int high = port->u.port.high_port; context_struct_t *con = &port->context[0]; int rec_proto = -1; sepol_context_t *tmp_con = NULL; sepol_port_t *tmp_record = NULL; if (sepol_port_create(handle, &tmp_record) < 0) goto err; rec_proto = ipproto2sepol(handle, proto); if (rec_proto < 0) goto err; sepol_port_set_proto(tmp_record, rec_proto); sepol_port_set_range(tmp_record, low, high); if (context_to_record(handle, policydb, con, &tmp_con) < 0) goto err; if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0) goto err; sepol_context_free(tmp_con); *record = tmp_record; return STATUS_SUCCESS; err: ERR(handle, "could not convert port range %u - %u (%s) " "to record", low, high, sepol_port_get_proto_str(rec_proto)); sepol_context_free(tmp_con); sepol_port_free(tmp_record); return STATUS_ERR; } /* Return the number of ports */ extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, unsigned int *response) { unsigned int count = 0; ocontext_t *c, *head; const policydb_t *policydb = &p->p; head = policydb->ocontexts[OCON_PORT]; for (c = head; c != NULL; c = c->next) count++; *response = count; handle = NULL; return STATUS_SUCCESS; } /* Check if a port exists */ int sepol_port_exists(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_port_key_t * key, int *response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; int low, high, proto; const char *proto_str; sepol_port_key_unpack(key, &low, &high, &proto); proto_str = sepol_port_get_proto_str(proto); proto = sepol2ipproto(handle, proto); if (proto < 0) goto err; head = policydb->ocontexts[OCON_PORT]; for (c = head; c; c = c->next) { int proto2 = c->u.port.protocol; int low2 = c->u.port.low_port; int high2 = c->u.port.high_port; if (proto == proto2 && low2 == low && high2 == high) { *response = 1; return STATUS_SUCCESS; } } *response = 0; return STATUS_SUCCESS; err: ERR(handle, "could not check if port range %u - %u (%s) exists", low, high, proto_str); return STATUS_ERR; } /* Query a port */ int sepol_port_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_port_key_t * key, sepol_port_t ** response) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; int low, high, proto; const char *proto_str; sepol_port_key_unpack(key, &low, &high, &proto); proto_str = sepol_port_get_proto_str(proto); proto = sepol2ipproto(handle, proto); if (proto < 0) goto err; head = policydb->ocontexts[OCON_PORT]; for (c = head; c; c = c->next) { int proto2 = c->u.port.protocol; int low2 = c->u.port.low_port; int high2 = c->u.port.high_port; if (proto == proto2 && low2 == low && high2 == high) { if (port_to_record(handle, policydb, c, response) < 0) goto err; return STATUS_SUCCESS; } } *response = NULL; return STATUS_SUCCESS; err: ERR(handle, "could not query port range %u - %u (%s)", low, high, proto_str); return STATUS_ERR; } /* Load a port into policy */ int sepol_port_modify(sepol_handle_t * handle, sepol_policydb_t * p, const sepol_port_key_t * key, const sepol_port_t * data) { policydb_t *policydb = &p->p; ocontext_t *port = NULL; int low, high, proto; const char *proto_str; sepol_port_key_unpack(key, &low, &high, &proto); proto_str = sepol_port_get_proto_str(proto); proto = sepol2ipproto(handle, proto); if (proto < 0) goto err; if (port_from_record(handle, policydb, &port, data) < 0) goto err; /* Attach to context list */ port->next = policydb->ocontexts[OCON_PORT]; policydb->ocontexts[OCON_PORT] = port; return STATUS_SUCCESS; err: ERR(handle, "could not load port range %u - %u (%s)", low, high, proto_str); if (port != NULL) { context_destroy(&port->context[0]); free(port); } return STATUS_ERR; } int sepol_port_iterate(sepol_handle_t * handle, const sepol_policydb_t * p, int (*fn) (const sepol_port_t * port, void *fn_arg), void *arg) { const policydb_t *policydb = &p->p; ocontext_t *c, *head; sepol_port_t *port = NULL; head = policydb->ocontexts[OCON_PORT]; for (c = head; c; c = c->next) { int status; if (port_to_record(handle, policydb, c, &port) < 0) goto err; /* Invoke handler */ status = fn(port, arg); if (status < 0) goto err; sepol_port_free(port); port = NULL; /* Handler requested exit */ if (status > 0) break; } return STATUS_SUCCESS; err: ERR(handle, "could not iterate over ports"); sepol_port_free(port); return STATUS_ERR; } libsepol-2.2/src/private.h000066400000000000000000000030061223423440700156000ustar00rootroot00000000000000/* Private definitions for libsepol. */ /* Endian conversion for reading and writing binary policies */ #include #ifdef DARWIN #include #include #else #include #include #endif #include #include #ifdef DARWIN #define __BYTE_ORDER BYTE_ORDER #define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_le16(x) (x) #define le16_to_cpu(x) (x) #define cpu_to_le32(x) (x) #define le32_to_cpu(x) (x) #define cpu_to_le64(x) (x) #define le64_to_cpu(x) (x) #else #define cpu_to_le16(x) bswap_16(x) #define le16_to_cpu(x) bswap_16(x) #define cpu_to_le32(x) bswap_32(x) #define le32_to_cpu(x) bswap_32(x) #define cpu_to_le64(x) bswap_64(x) #define le64_to_cpu(x) bswap_64(x) #endif #undef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #undef max #define max(a,b) ((a) >= (b) ? (a) : (b)) #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /* Policy compatibility information. */ struct policydb_compat_info { unsigned int type; unsigned int version; unsigned int sym_num; unsigned int ocon_num; unsigned int target_platform; }; extern struct policydb_compat_info *policydb_lookup_compat(unsigned int version, unsigned int type, unsigned int target_platform); /* Reading from a policy "file". */ extern int next_entry(void *buf, struct policy_file *fp, size_t bytes) hidden; extern size_t put_entry(const void *ptr, size_t size, size_t n, struct policy_file *fp) hidden; libsepol-2.2/src/roles.c000066400000000000000000000023101223423440700152420ustar00rootroot00000000000000#include #include #include #include #include "debug.h" #include "handle.h" /* Check if a role exists */ int sepol_role_exists(sepol_handle_t * handle __attribute__ ((unused)), sepol_policydb_t * p, const char *role, int *response) { policydb_t *policydb = &p->p; *response = (hashtab_search(policydb->p_roles.table, (const hashtab_key_t)role) != NULL); handle = NULL; return STATUS_SUCCESS; } /* Fill an array with all valid roles */ int sepol_role_list(sepol_handle_t * handle, sepol_policydb_t * p, char ***roles, unsigned int *nroles) { policydb_t *policydb = &p->p; unsigned int tmp_nroles = policydb->p_roles.nprim; char **tmp_roles = (char **)malloc(tmp_nroles * sizeof(char *)); char **ptr; unsigned int i; if (!tmp_roles) goto omem; for (i = 0; i < tmp_nroles; i++) { tmp_roles[i] = strdup(policydb->p_role_val_to_name[i]); if (!tmp_roles[i]) goto omem; } *nroles = tmp_nroles; *roles = tmp_roles; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not list roles"); ptr = tmp_roles; while (ptr && *ptr) free(*ptr++); free(tmp_roles); return STATUS_ERR; } libsepol-2.2/src/services.c000066400000000000000000001443641223423440700157610ustar00rootroot00000000000000 /* * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: Frank Mayer * and Karl MacMillan * * Added conditional policy language extensions * * Updated: Red Hat, Inc. James Morris * * Fine-grained netlink support * IPv6 support * Code cleanup * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2003 - 2004 Red Hat, Inc. * * 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 */ /* FLASK */ /* * Implementation of the security services. */ /* Initial sizes malloc'd for sepol_compute_av_reason_buffer() support */ #define REASON_BUF_SIZE 2048 #define EXPR_BUF_SIZE 1024 #define STACK_LEN 32 #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "private.h" #include "context.h" #include "av_permissions.h" #include "dso.h" #include "mls.h" #define BUG() do { ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0) #define BUG_ON(x) do { if (x) ERR(NULL, "Badness at %s:%d", __FILE__, __LINE__); } while (0) static int selinux_enforcing = 1; static sidtab_t mysidtab, *sidtab = &mysidtab; static policydb_t mypolicydb, *policydb = &mypolicydb; /* Used by sepol_compute_av_reason_buffer() to keep track of entries */ static int reason_buf_used; static int reason_buf_len; /* Stack services for RPN to infix conversion. */ static char **stack; static int stack_len; static int next_stack_entry; static void push(char *expr_ptr) { if (next_stack_entry >= stack_len) { char **new_stack = stack; int new_stack_len; if (stack_len == 0) new_stack_len = STACK_LEN; else new_stack_len = stack_len * 2; new_stack = realloc(stack, new_stack_len * sizeof(*stack)); if (!new_stack) { ERR(NULL, "unable to allocate stack space"); return; } stack_len = new_stack_len; stack = new_stack; } stack[next_stack_entry] = expr_ptr; next_stack_entry++; } static char *pop(void) { next_stack_entry--; if (next_stack_entry < 0) { next_stack_entry = 0; ERR(NULL, "pop called with no stack entries"); return NULL; } return stack[next_stack_entry]; } /* End Stack services */ int hidden sepol_set_sidtab(sidtab_t * s) { sidtab = s; return 0; } int hidden sepol_set_policydb(policydb_t * p) { policydb = p; return 0; } int sepol_set_policydb_from_file(FILE * fp) { struct policy_file pf; policy_file_init(&pf); pf.fp = fp; pf.type = PF_USE_STDIO; if (mypolicydb.policy_type) policydb_destroy(&mypolicydb); if (policydb_init(&mypolicydb)) { ERR(NULL, "Out of memory!"); return -1; } if (policydb_read(&mypolicydb, &pf, 0)) { policydb_destroy(&mypolicydb); ERR(NULL, "can't read binary policy: %s", strerror(errno)); return -1; } policydb = &mypolicydb; return sepol_sidtab_init(sidtab); } /* * The largest sequence number that has been used when * providing an access decision to the access vector cache. * The sequence number only changes when a policy change * occurs. */ static uint32_t latest_granting = 0; /* * cat_expr_buf adds a string to an expression buffer and handles * realloc's if buffer is too small. The array of expression text * buffer pointers and its counter are globally defined here as * constraint_expr_eval_reason() sets them up and cat_expr_buf * updates the e_buf pointer. */ static int expr_counter; static char **expr_list; static int expr_buf_used; static int expr_buf_len; static void cat_expr_buf(char *e_buf, char *string) { int len, new_buf_len; char *p, *new_buf = e_buf; while (1) { p = e_buf + expr_buf_used; len = snprintf(p, expr_buf_len - expr_buf_used, "%s", string); if (len < 0 || len >= expr_buf_len - expr_buf_used) { new_buf_len = expr_buf_len + EXPR_BUF_SIZE; new_buf = realloc(e_buf, new_buf_len); if (!new_buf) { ERR(NULL, "failed to realloc expr buffer"); return; } /* Update new ptr in expr list and locally + new len */ expr_list[expr_counter] = new_buf; e_buf = new_buf; expr_buf_len = new_buf_len; } else { expr_buf_used += len; return; } } } /* * If the POLICY_KERN version is >= POLICYDB_VERSION_CONSTRAINT_NAMES, * then for 'types' only, read the types_names->types list as it will * contain a list of types and attributes that were defined in the * policy source. * For user and role plus types (for policy vers < * POLICYDB_VERSION_CONSTRAINT_NAMES) just read the e->names list. */ static void get_name_list(constraint_expr_t *e, int type, char *src, char *op, int failed) { ebitmap_t *types; int rc = 0; unsigned int i; char tmp_buf[128]; int counter = 0; if (policydb->policy_type == POLICY_KERN && policydb->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES && type == CEXPR_TYPE) types = &e->type_names->types; else types = &e->names; /* Find out how many entries */ for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) { rc = ebitmap_get_bit(types, i); if (rc == 0) continue; else counter++; } snprintf(tmp_buf, sizeof(tmp_buf), "(%s%s", src, op); cat_expr_buf(expr_list[expr_counter], tmp_buf); if (counter == 0) cat_expr_buf(expr_list[expr_counter], " "); if (counter > 1) cat_expr_buf(expr_list[expr_counter], " {"); if (counter >= 1) { for (i = ebitmap_startbit(types); i < ebitmap_length(types); i++) { rc = ebitmap_get_bit(types, i); if (rc == 0) continue; /* Collect entries */ switch (type) { case CEXPR_USER: snprintf(tmp_buf, sizeof(tmp_buf), " %s", policydb->p_user_val_to_name[i]); break; case CEXPR_ROLE: snprintf(tmp_buf, sizeof(tmp_buf), " %s", policydb->p_role_val_to_name[i]); break; case CEXPR_TYPE: snprintf(tmp_buf, sizeof(tmp_buf), " %s", policydb->p_type_val_to_name[i]); break; } cat_expr_buf(expr_list[expr_counter], tmp_buf); } } if (counter > 1) cat_expr_buf(expr_list[expr_counter], " }"); if (failed) cat_expr_buf(expr_list[expr_counter], " -Fail-) "); else cat_expr_buf(expr_list[expr_counter], ") "); return; } static void msgcat(char *src, char *tgt, char *op, int failed) { char tmp_buf[128]; if (failed) snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s -Fail-) ", src, op, tgt); else snprintf(tmp_buf, sizeof(tmp_buf), "(%s %s %s) ", src, op, tgt); cat_expr_buf(expr_list[expr_counter], tmp_buf); } /* Returns a buffer with class, statement type and permissions */ static char *get_class_info(sepol_security_class_t tclass, constraint_node_t *constraint, context_struct_t *xcontext) { constraint_expr_t *e; int mls, state_num; /* Find if MLS statement or not */ mls = 0; for (e = constraint->expr; e; e = e->next) { if (e->attr >= CEXPR_L1L2) { mls = 1; break; } } /* Determine statement type */ char *statements[] = { "constrain ", /* 0 */ "mlsconstrain ", /* 1 */ "validatetrans ", /* 2 */ "mlsvalidatetrans ", /* 3 */ 0 }; if (xcontext == NULL) state_num = mls + 0; else state_num = mls + 2; int class_buf_len = 0; int new_class_buf_len; int len, buf_used; char *class_buf = NULL, *p; char *new_class_buf = NULL; while (1) { new_class_buf_len = class_buf_len + EXPR_BUF_SIZE; new_class_buf = realloc(class_buf, new_class_buf_len); if (!new_class_buf) return NULL; class_buf_len = new_class_buf_len; class_buf = new_class_buf; buf_used = 0; p = class_buf; /* Add statement type */ len = snprintf(p, class_buf_len - buf_used, "%s", statements[state_num]); if (len < 0 || len >= class_buf_len - buf_used) continue; /* Add class entry */ p += len; buf_used += len; len = snprintf(p, class_buf_len - buf_used, "%s ", policydb->p_class_val_to_name[tclass - 1]); if (len < 0 || len >= class_buf_len - buf_used) continue; /* Add permission entries */ p += len; buf_used += len; len = snprintf(p, class_buf_len - buf_used, "{%s } (", sepol_av_to_string(policydb, tclass, constraint->permissions)); if (len < 0 || len >= class_buf_len - buf_used) continue; break; } return class_buf; } /* * Modified version of constraint_expr_eval that will process each * constraint as before but adds the information to text buffers that * will hold various components. The expression will be in RPN format, * therefore there is a stack based RPN to infix converter to produce * the final readable constraint. * * Return the boolean value of a constraint expression * when it is applied to the specified source and target * security contexts. * * xcontext is a special beast... It is used by the validatetrans rules * only. For these rules, scontext is the context before the transition, * tcontext is the context after the transition, and xcontext is the * context of the process performing the transition. All other callers * of constraint_expr_eval_reason should pass in NULL for xcontext. * * This function will also build a buffer as the constraint is processed * for analysis. If this option is not required, then: * 'tclass' should be '0' and r_buf MUST be NULL. */ static int constraint_expr_eval_reason(context_struct_t *scontext, context_struct_t *tcontext, context_struct_t *xcontext, sepol_security_class_t tclass, constraint_node_t *constraint, char **r_buf, unsigned int flags) { uint32_t val1, val2; context_struct_t *c; role_datum_t *r1, *r2; mls_level_t *l1, *l2; constraint_expr_t *e; int s[CEXPR_MAXDEPTH]; int sp = -1; char tmp_buf[128]; /* * Define the s_t_x_num values that make up r1, t2 etc. in text strings * Set 1 = source, 2 = target, 3 = xcontext for validatetrans */ #define SOURCE 1 #define TARGET 2 #define XTARGET 3 int s_t_x_num = SOURCE; /* Set 0 = fail, u = CEXPR_USER, r = CEXPR_ROLE, t = CEXPR_TYPE */ int u_r_t = 0; char *src = NULL; char *tgt = NULL; int rc = 0, x; char *class_buf = NULL; class_buf = get_class_info(tclass, constraint, xcontext); if (!class_buf) { ERR(NULL, "failed to allocate class buffer"); return -ENOMEM; } /* Original function but with buffer support */ int expr_list_len = 0; expr_counter = 0; expr_list = NULL; for (e = constraint->expr; e; e = e->next) { /* Allocate a stack to hold expression buffer entries */ if (expr_counter >= expr_list_len) { char **new_expr_list = expr_list; int new_expr_list_len; if (expr_list_len == 0) new_expr_list_len = STACK_LEN; else new_expr_list_len = expr_list_len * 2; new_expr_list = realloc(expr_list, new_expr_list_len * sizeof(*expr_list)); if (!new_expr_list) { ERR(NULL, "failed to allocate expr buffer stack"); rc = -ENOMEM; goto out; } expr_list_len = new_expr_list_len; expr_list = new_expr_list; } /* * malloc a buffer to store each expression text component. If * buffer is too small cat_expr_buf() will realloc extra space. */ expr_buf_len = EXPR_BUF_SIZE; expr_list[expr_counter] = malloc(expr_buf_len); if (!expr_list[expr_counter]) { ERR(NULL, "failed to allocate expr buffer"); rc = -ENOMEM; goto out; } expr_buf_used = 0; /* Now process each expression of the constraint */ switch (e->expr_type) { case CEXPR_NOT: BUG_ON(sp < 0); s[sp] = !s[sp]; cat_expr_buf(expr_list[expr_counter], "not"); break; case CEXPR_AND: BUG_ON(sp < 1); sp--; s[sp] &= s[sp + 1]; cat_expr_buf(expr_list[expr_counter], "and"); break; case CEXPR_OR: BUG_ON(sp < 1); sp--; s[sp] |= s[sp + 1]; cat_expr_buf(expr_list[expr_counter], "or"); break; case CEXPR_ATTR: if (sp == (CEXPR_MAXDEPTH - 1)) goto out; switch (e->attr) { case CEXPR_USER: val1 = scontext->user; val2 = tcontext->user; free(src); src = strdup("u1"); free(tgt); tgt = strdup("u2"); break; case CEXPR_TYPE: val1 = scontext->type; val2 = tcontext->type; free(src); src = strdup("t1"); free(tgt); tgt = strdup("t2"); break; case CEXPR_ROLE: val1 = scontext->role; val2 = tcontext->role; r1 = policydb->role_val_to_struct[val1 - 1]; r2 = policydb->role_val_to_struct[val2 - 1]; free(src); src = strdup("r1"); free(tgt); tgt = strdup("r2"); switch (e->op) { case CEXPR_DOM: s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1); msgcat(src, tgt, "dom", s[sp] == 0); expr_counter++; continue; case CEXPR_DOMBY: s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1); msgcat(src, tgt, "domby", s[sp] == 0); expr_counter++; continue; case CEXPR_INCOMP: s[++sp] = (!ebitmap_get_bit(&r1->dominates, val2 - 1) && !ebitmap_get_bit(&r2->dominates, val1 - 1)); msgcat(src, tgt, "incomp", s[sp] == 0); expr_counter++; continue; default: break; } break; case CEXPR_L1L2: l1 = &(scontext->range.level[0]); l2 = &(tcontext->range.level[0]); free(src); src = strdup("l1"); free(tgt); tgt = strdup("l2"); goto mls_ops; case CEXPR_L1H2: l1 = &(scontext->range.level[0]); l2 = &(tcontext->range.level[1]); free(src); src = strdup("l1"); free(tgt); tgt = strdup("h2"); goto mls_ops; case CEXPR_H1L2: l1 = &(scontext->range.level[1]); l2 = &(tcontext->range.level[0]); free(src); src = strdup("h1"); free(tgt); tgt = strdup("l2"); goto mls_ops; case CEXPR_H1H2: l1 = &(scontext->range.level[1]); l2 = &(tcontext->range.level[1]); free(src); src = strdup("h1"); free(tgt); tgt = strdup("h2"); goto mls_ops; case CEXPR_L1H1: l1 = &(scontext->range.level[0]); l2 = &(scontext->range.level[1]); free(src); src = strdup("l1"); free(tgt); tgt = strdup("h1"); goto mls_ops; case CEXPR_L2H2: l1 = &(tcontext->range.level[0]); l2 = &(tcontext->range.level[1]); free(src); src = strdup("l2"); free(tgt); tgt = strdup("h2"); mls_ops: switch (e->op) { case CEXPR_EQ: s[++sp] = mls_level_eq(l1, l2); msgcat(src, tgt, "eq", s[sp] == 0); expr_counter++; continue; case CEXPR_NEQ: s[++sp] = !mls_level_eq(l1, l2); msgcat(src, tgt, "!=", s[sp] == 0); expr_counter++; continue; case CEXPR_DOM: s[++sp] = mls_level_dom(l1, l2); msgcat(src, tgt, "dom", s[sp] == 0); expr_counter++; continue; case CEXPR_DOMBY: s[++sp] = mls_level_dom(l2, l1); msgcat(src, tgt, "domby", s[sp] == 0); expr_counter++; continue; case CEXPR_INCOMP: s[++sp] = mls_level_incomp(l2, l1); msgcat(src, tgt, "incomp", s[sp] == 0); expr_counter++; continue; default: BUG(); goto out; } break; default: BUG(); goto out; } switch (e->op) { case CEXPR_EQ: s[++sp] = (val1 == val2); msgcat(src, tgt, "==", s[sp] == 0); break; case CEXPR_NEQ: s[++sp] = (val1 != val2); msgcat(src, tgt, "!=", s[sp] == 0); break; default: BUG(); goto out; } break; case CEXPR_NAMES: if (sp == (CEXPR_MAXDEPTH - 1)) goto out; s_t_x_num = SOURCE; c = scontext; if (e->attr & CEXPR_TARGET) { s_t_x_num = TARGET; c = tcontext; } else if (e->attr & CEXPR_XTARGET) { s_t_x_num = XTARGET; c = xcontext; } if (!c) { BUG(); goto out; } if (e->attr & CEXPR_USER) { u_r_t = CEXPR_USER; val1 = c->user; snprintf(tmp_buf, sizeof(tmp_buf), "u%d ", s_t_x_num); free(src); src = strdup(tmp_buf); } else if (e->attr & CEXPR_ROLE) { u_r_t = CEXPR_ROLE; val1 = c->role; snprintf(tmp_buf, sizeof(tmp_buf), "r%d ", s_t_x_num); free(src); src = strdup(tmp_buf); } else if (e->attr & CEXPR_TYPE) { u_r_t = CEXPR_TYPE; val1 = c->type; snprintf(tmp_buf, sizeof(tmp_buf), "t%d ", s_t_x_num); free(src); src = strdup(tmp_buf); } else { BUG(); goto out; } switch (e->op) { case CEXPR_EQ: s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); get_name_list(e, u_r_t, src, "==", s[sp] == 0); break; case CEXPR_NEQ: s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); get_name_list(e, u_r_t, src, "!=", s[sp] == 0); break; default: BUG(); goto out; } break; default: BUG(); goto out; } expr_counter++; } /* * At this point each expression of the constraint is in * expr_list[n+1] and in RPN format. Now convert to 'infix' */ /* * Save expr count but zero expr_counter to detect if * 'BUG(); goto out;' was called as we need to release any used * expr_list malloc's. Normally they are released by the RPN to * infix code. */ int expr_count = expr_counter; expr_counter = 0; /* * The array of expression answer buffer pointers and counter. * Generate the same number of answer buffer entries as expression * buffers (as there will never be more). */ char **answer_list; int answer_counter = 0; answer_list = malloc(expr_count * sizeof(*answer_list)); if (!answer_list) { ERR(NULL, "failed to allocate answer stack"); rc = -ENOMEM; goto out; } /* The pop operands */ char *a; char *b; int a_len, b_len; /* Convert constraint from RPN to infix notation. */ for (x = 0; x != expr_count; x++) { if (strncmp(expr_list[x], "and", 3) == 0 || strncmp(expr_list[x], "or", 2) == 0) { b = pop(); b_len = strlen(b); a = pop(); a_len = strlen(a); /* get a buffer to hold the answer */ answer_list[answer_counter] = malloc(a_len + b_len + 8); if (!answer_list[answer_counter]) { ERR(NULL, "failed to allocate answer buffer"); rc = -ENOMEM; goto out; } memset(answer_list[answer_counter], '\0', a_len + b_len + 8); sprintf(answer_list[answer_counter], "%s %s %s", a, expr_list[x], b); push(answer_list[answer_counter++]); free(a); free(b); } else if (strncmp(expr_list[x], "not", 3) == 0) { b = pop(); b_len = strlen(b); answer_list[answer_counter] = malloc(b_len + 8); if (!answer_list[answer_counter]) { ERR(NULL, "failed to allocate answer buffer"); rc = -ENOMEM; goto out; } memset(answer_list[answer_counter], '\0', b_len + 8); if (strncmp(b, "not", 3) == 0) sprintf(answer_list[answer_counter], "%s (%s)", expr_list[x], b); else sprintf(answer_list[answer_counter], "%s%s", expr_list[x], b); push(answer_list[answer_counter++]); free(b); } else { push(expr_list[x]); } } /* Get the final answer from tos and build constraint text */ a = pop(); /* Constraint calculation: rc = 0 is denied, rc = 1 is granted */ sprintf(tmp_buf, "Constraint %s\n", s[0] ? "GRANTED" : "DENIED"); int len, new_buf_len; char *p, **new_buf = r_buf; /* * These contain the constraint components that are added to the * callers reason buffer. */ char *buffers[] = { class_buf, a, "); ", tmp_buf, 0 }; /* * This will add the constraints to the callers reason buffer (who is * responsible for freeing the memory). It will handle any realloc's * should the buffer be too short. * The reason_buf_used and reason_buf_len counters are defined * globally as multiple constraints can be in the buffer. */ if (r_buf && ((s[0] == 0) || ((s[0] == 1 && (flags & SHOW_GRANTED) == SHOW_GRANTED)))) { for (x = 0; buffers[x] != NULL; x++) { while (1) { p = *r_buf + reason_buf_used; len = snprintf(p, reason_buf_len - reason_buf_used, "%s", buffers[x]); if (len < 0 || len >= reason_buf_len - reason_buf_used) { new_buf_len = reason_buf_len + REASON_BUF_SIZE; *new_buf = realloc(*r_buf, new_buf_len); if (!new_buf) { ERR(NULL, "failed to realloc reason buffer"); goto out1; } **r_buf = **new_buf; reason_buf_len = new_buf_len; continue; } else { reason_buf_used += len; break; } } } } out1: rc = s[0]; free(a); out: free(class_buf); free(src); free(tgt); if (expr_counter) { for (x = 0; expr_list[x] != NULL; x++) free(expr_list[x]); } return rc; } /* * Compute access vectors based on a context structure pair for * the permissions in a particular class. */ static int context_struct_compute_av(context_struct_t * scontext, context_struct_t * tcontext, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, unsigned int *reason, char **r_buf, unsigned int flags) { constraint_node_t *constraint; struct role_allow *ra; avtab_key_t avkey; class_datum_t *tclass_datum; avtab_ptr_t node; ebitmap_t *sattr, *tattr; ebitmap_node_t *snode, *tnode; unsigned int i, j; if (!tclass || tclass > policydb->p_classes.nprim) { ERR(NULL, "unrecognized class %d", tclass); return -EINVAL; } tclass_datum = policydb->class_val_to_struct[tclass - 1]; /* * Initialize the access vectors to the default values. */ avd->allowed = 0; avd->decided = 0xffffffff; avd->auditallow = 0; avd->auditdeny = 0xffffffff; avd->seqno = latest_granting; *reason = 0; /* * If a specific type enforcement rule was defined for * this permission check, then use it. */ avkey.target_class = tclass; avkey.specified = AVTAB_AV; sattr = &policydb->type_attr_map[scontext->type - 1]; tattr = &policydb->type_attr_map[tcontext->type - 1]; ebitmap_for_each_bit(sattr, snode, i) { if (!ebitmap_node_get_bit(snode, i)) continue; ebitmap_for_each_bit(tattr, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; avkey.source_type = i + 1; avkey.target_type = j + 1; for (node = avtab_search_node(&policydb->te_avtab, &avkey); node != NULL; node = avtab_search_node_next(node, avkey.specified)) { if (node->key.specified == AVTAB_ALLOWED) avd->allowed |= node->datum.data; else if (node->key.specified == AVTAB_AUDITALLOW) avd->auditallow |= node->datum.data; else if (node->key.specified == AVTAB_AUDITDENY) avd->auditdeny &= node->datum.data; } /* Check conditional av table for additional permissions */ cond_compute_av(&policydb->te_cond_avtab, &avkey, avd); } } if (requested & ~avd->allowed) { *reason |= SEPOL_COMPUTEAV_TE; requested &= avd->allowed; } /* * Remove any permissions prohibited by a constraint (this includes * the MLS policy). */ constraint = tclass_datum->constraints; while (constraint) { if ((constraint->permissions & (avd->allowed)) && !constraint_expr_eval_reason(scontext, tcontext, NULL, tclass, constraint, r_buf, flags)) { avd->allowed = (avd->allowed) & ~(constraint->permissions); } constraint = constraint->next; } if (requested & ~avd->allowed) { *reason |= SEPOL_COMPUTEAV_CONS; requested &= avd->allowed; } /* * If checking process transition permission and the * role is changing, then check the (current_role, new_role) * pair. */ if (tclass == SECCLASS_PROCESS && (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) && scontext->role != tcontext->role) { for (ra = policydb->role_allow; ra; ra = ra->next) { if (scontext->role == ra->role && tcontext->role == ra->new_role) break; } if (!ra) avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | PROCESS__DYNTRANSITION); } if (requested & ~avd->allowed) { *reason |= SEPOL_COMPUTEAV_RBAC; requested &= avd->allowed; } return 0; } int hidden sepol_validate_transition(sepol_security_id_t oldsid, sepol_security_id_t newsid, sepol_security_id_t tasksid, sepol_security_class_t tclass) { context_struct_t *ocontext; context_struct_t *ncontext; context_struct_t *tcontext; class_datum_t *tclass_datum; constraint_node_t *constraint; if (!tclass || tclass > policydb->p_classes.nprim) { ERR(NULL, "unrecognized class %d", tclass); return -EINVAL; } tclass_datum = policydb->class_val_to_struct[tclass - 1]; ocontext = sepol_sidtab_search(sidtab, oldsid); if (!ocontext) { ERR(NULL, "unrecognized SID %d", oldsid); return -EINVAL; } ncontext = sepol_sidtab_search(sidtab, newsid); if (!ncontext) { ERR(NULL, "unrecognized SID %d", newsid); return -EINVAL; } tcontext = sepol_sidtab_search(sidtab, tasksid); if (!tcontext) { ERR(NULL, "unrecognized SID %d", tasksid); return -EINVAL; } constraint = tclass_datum->validatetrans; while (constraint) { if (!constraint_expr_eval_reason(ocontext, ncontext, tcontext, 0, constraint, NULL, 0)) { return -EPERM; } constraint = constraint->next; } return 0; } int hidden sepol_compute_av_reason(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, unsigned int *reason) { context_struct_t *scontext = 0, *tcontext = 0; int rc = 0; scontext = sepol_sidtab_search(sidtab, ssid); if (!scontext) { ERR(NULL, "unrecognized SID %d", ssid); rc = -EINVAL; goto out; } tcontext = sepol_sidtab_search(sidtab, tsid); if (!tcontext) { ERR(NULL, "unrecognized SID %d", tsid); rc = -EINVAL; goto out; } rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd, reason, NULL, 0); out: return rc; } /* * sepol_compute_av_reason_buffer - the reason buffer is malloc'd to * REASON_BUF_SIZE. If the buffer size is exceeded, then it is realloc'd * in the constraint_expr_eval_reason() function. */ int hidden sepol_compute_av_reason_buffer(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, unsigned int *reason, char **reason_buf, unsigned int flags) { context_struct_t *scontext = 0, *tcontext = 0; int rc = 0; scontext = sepol_sidtab_search(sidtab, ssid); if (!scontext) { ERR(NULL, "unrecognized SID %d", ssid); rc = -EINVAL; goto out; } tcontext = sepol_sidtab_search(sidtab, tsid); if (!tcontext) { ERR(NULL, "unrecognized SID %d", tsid); rc = -EINVAL; goto out; } /* * Set the buffer to NULL as constraints may not be processed. * If a buffer is required, then the routines in * constraint_expr_eval_reason will realloc in REASON_BUF_SIZE * chunks (as it gets called for each constraint processed). * We just make sure these start from zero. */ *reason_buf = NULL; reason_buf_used = 0; reason_buf_len = 0; rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd, reason, reason_buf, flags); out: return rc; } int hidden sepol_compute_av(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd) { unsigned int reason = 0; return sepol_compute_av_reason(ssid, tsid, tclass, requested, avd, &reason); } /* * Return a class ID associated with the class string specified by * class_name. */ int hidden sepol_string_to_security_class(const char *class_name, sepol_security_class_t *tclass) { char *class = NULL; sepol_security_class_t id; for (id = 1;; id++) { class = policydb->p_class_val_to_name[id - 1]; if (class == NULL) { ERR(NULL, "could not convert %s to class id", class_name); return STATUS_ERR; } if ((strcmp(class, class_name)) == 0) { *tclass = id; return STATUS_SUCCESS; } } } /* * Return access vector bit associated with the class ID and permission * string. */ int hidden sepol_string_to_av_perm(sepol_security_class_t tclass, const char *perm_name, sepol_access_vector_t *av) { class_datum_t *tclass_datum; perm_datum_t *perm_datum; if (!tclass || tclass > policydb->p_classes.nprim) { ERR(NULL, "unrecognized class %d", tclass); return -EINVAL; } tclass_datum = policydb->class_val_to_struct[tclass - 1]; /* Check for unique perms then the common ones (if any) */ perm_datum = (perm_datum_t *) hashtab_search(tclass_datum->permissions.table, (hashtab_key_t)perm_name); if (perm_datum != NULL) { *av = 0x1 << (perm_datum->s.value - 1); return STATUS_SUCCESS; } if (tclass_datum->comdatum == NULL) goto out; perm_datum = (perm_datum_t *) hashtab_search(tclass_datum->comdatum->permissions.table, (hashtab_key_t)perm_name); if (perm_datum != NULL) { *av = 0x1 << (perm_datum->s.value - 1); return STATUS_SUCCESS; } out: ERR(NULL, "could not convert %s to av bit", perm_name); return STATUS_ERR; } /* * Write the security context string representation of * the context associated with `sid' into a dynamically * allocated string of the correct size. Set `*scontext' * to point to this string and set `*scontext_len' to * the length of the string. */ int hidden sepol_sid_to_context(sepol_security_id_t sid, sepol_security_context_t * scontext, size_t * scontext_len) { context_struct_t *context; int rc = 0; context = sepol_sidtab_search(sidtab, sid); if (!context) { ERR(NULL, "unrecognized SID %d", sid); rc = -EINVAL; goto out; } rc = context_to_string(NULL, policydb, context, scontext, scontext_len); out: return rc; } /* * Return a SID associated with the security context that * has the string representation specified by `scontext'. */ int hidden sepol_context_to_sid(const sepol_security_context_t scontext, size_t scontext_len, sepol_security_id_t * sid) { context_struct_t *context = NULL; /* First, create the context */ if (context_from_string(NULL, policydb, &context, scontext, scontext_len) < 0) goto err; /* Obtain the new sid */ if (sid && (sepol_sidtab_context_to_sid(sidtab, context, sid) < 0)) goto err; context_destroy(context); free(context); return STATUS_SUCCESS; err: if (context) { context_destroy(context); free(context); } ERR(NULL, "could not convert %s to sid", scontext); return STATUS_ERR; } static inline int compute_sid_handle_invalid_context(context_struct_t * scontext, context_struct_t * tcontext, sepol_security_class_t tclass, context_struct_t * newcontext) { if (selinux_enforcing) { return -EACCES; } else { sepol_security_context_t s, t, n; size_t slen, tlen, nlen; context_to_string(NULL, policydb, scontext, &s, &slen); context_to_string(NULL, policydb, tcontext, &t, &tlen); context_to_string(NULL, policydb, newcontext, &n, &nlen); ERR(NULL, "invalid context %s for " "scontext=%s tcontext=%s tclass=%s", n, s, t, policydb->p_class_val_to_name[tclass - 1]); free(s); free(t); free(n); return 0; } } static int sepol_compute_sid(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, uint32_t specified, sepol_security_id_t * out_sid) { context_struct_t *scontext = 0, *tcontext = 0, newcontext; struct role_trans *roletr = 0; avtab_key_t avkey; avtab_datum_t *avdatum; avtab_ptr_t node; int rc = 0; scontext = sepol_sidtab_search(sidtab, ssid); if (!scontext) { ERR(NULL, "unrecognized SID %d", ssid); rc = -EINVAL; goto out; } tcontext = sepol_sidtab_search(sidtab, tsid); if (!tcontext) { ERR(NULL, "unrecognized SID %d", tsid); rc = -EINVAL; goto out; } context_init(&newcontext); /* Set the user identity. */ switch (specified) { case AVTAB_TRANSITION: case AVTAB_CHANGE: /* Use the process user identity. */ newcontext.user = scontext->user; break; case AVTAB_MEMBER: /* Use the related object owner. */ newcontext.user = tcontext->user; break; } /* Set the role and type to default values. */ switch (tclass) { case SECCLASS_PROCESS: /* Use the current role and type of process. */ newcontext.role = scontext->role; newcontext.type = scontext->type; break; default: /* Use the well-defined object role. */ newcontext.role = OBJECT_R_VAL; /* Use the type of the related object. */ newcontext.type = tcontext->type; } /* Look for a type transition/member/change rule. */ avkey.source_type = scontext->type; avkey.target_type = tcontext->type; avkey.target_class = tclass; avkey.specified = specified; avdatum = avtab_search(&policydb->te_avtab, &avkey); /* If no permanent rule, also check for enabled conditional rules */ if (!avdatum) { node = avtab_search_node(&policydb->te_cond_avtab, &avkey); for (; node != NULL; node = avtab_search_node_next(node, specified)) { if (node->key.specified & AVTAB_ENABLED) { avdatum = &node->datum; break; } } } if (avdatum) { /* Use the type from the type transition/member/change rule. */ newcontext.type = avdatum->data; } /* Check for class-specific changes. */ switch (tclass) { case SECCLASS_PROCESS: if (specified & AVTAB_TRANSITION) { /* Look for a role transition rule. */ for (roletr = policydb->role_tr; roletr; roletr = roletr->next) { if (roletr->role == scontext->role && roletr->type == tcontext->type) { /* Use the role transition rule. */ newcontext.role = roletr->new_role; break; } } } break; default: break; } /* Set the MLS attributes. This is done last because it may allocate memory. */ rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified, &newcontext); if (rc) goto out; /* Check the validity of the context. */ if (!policydb_context_isvalid(policydb, &newcontext)) { rc = compute_sid_handle_invalid_context(scontext, tcontext, tclass, &newcontext); if (rc) goto out; } /* Obtain the sid for the context. */ rc = sepol_sidtab_context_to_sid(sidtab, &newcontext, out_sid); out: context_destroy(&newcontext); return rc; } /* * Compute a SID to use for labeling a new object in the * class `tclass' based on a SID pair. */ int hidden sepol_transition_sid(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_security_id_t * out_sid) { return sepol_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid); } /* * Compute a SID to use when selecting a member of a * polyinstantiated object of class `tclass' based on * a SID pair. */ int hidden sepol_member_sid(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_security_id_t * out_sid) { return sepol_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid); } /* * Compute a SID to use for relabeling an object in the * class `tclass' based on a SID pair. */ int hidden sepol_change_sid(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, sepol_security_id_t * out_sid) { return sepol_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); } /* * Verify that each permission that is defined under the * existing policy is still defined with the same value * in the new policy. */ static int validate_perm(hashtab_key_t key, hashtab_datum_t datum, void *p) { hashtab_t h; perm_datum_t *perdatum, *perdatum2; h = (hashtab_t) p; perdatum = (perm_datum_t *) datum; perdatum2 = (perm_datum_t *) hashtab_search(h, key); if (!perdatum2) { ERR(NULL, "permission %s disappeared", key); return -1; } if (perdatum->s.value != perdatum2->s.value) { ERR(NULL, "the value of permissions %s changed", key); return -1; } return 0; } /* * Verify that each class that is defined under the * existing policy is still defined with the same * attributes in the new policy. */ static int validate_class(hashtab_key_t key, hashtab_datum_t datum, void *p) { policydb_t *newp; class_datum_t *cladatum, *cladatum2; newp = (policydb_t *) p; cladatum = (class_datum_t *) datum; cladatum2 = (class_datum_t *) hashtab_search(newp->p_classes.table, key); if (!cladatum2) { ERR(NULL, "class %s disappeared", key); return -1; } if (cladatum->s.value != cladatum2->s.value) { ERR(NULL, "the value of class %s changed", key); return -1; } if ((cladatum->comdatum && !cladatum2->comdatum) || (!cladatum->comdatum && cladatum2->comdatum)) { ERR(NULL, "the inherits clause for the access " "vector definition for class %s changed", key); return -1; } if (cladatum->comdatum) { if (hashtab_map (cladatum->comdatum->permissions.table, validate_perm, cladatum2->comdatum->permissions.table)) { ERR(NULL, " in the access vector definition " "for class %s\n", key); return -1; } } if (hashtab_map(cladatum->permissions.table, validate_perm, cladatum2->permissions.table)) { ERR(NULL, " in access vector definition for class %s", key); return -1; } return 0; } /* Clone the SID into the new SID table. */ static int clone_sid(sepol_security_id_t sid, context_struct_t * context, void *arg) { sidtab_t *s = arg; return sepol_sidtab_insert(s, sid, context); } static inline int convert_context_handle_invalid_context(context_struct_t * context) { if (selinux_enforcing) { return -EINVAL; } else { sepol_security_context_t s; size_t len; context_to_string(NULL, policydb, context, &s, &len); ERR(NULL, "context %s is invalid", s); free(s); return 0; } } typedef struct { policydb_t *oldp; policydb_t *newp; } convert_context_args_t; /* * Convert the values in the security context * structure `c' from the values specified * in the policy `p->oldp' to the values specified * in the policy `p->newp'. Verify that the * context is valid under the new policy. */ static int convert_context(sepol_security_id_t key __attribute__ ((unused)), context_struct_t * c, void *p) { convert_context_args_t *args; context_struct_t oldc; role_datum_t *role; type_datum_t *typdatum; user_datum_t *usrdatum; sepol_security_context_t s; size_t len; int rc = -EINVAL; args = (convert_context_args_t *) p; if (context_cpy(&oldc, c)) return -ENOMEM; /* Convert the user. */ usrdatum = (user_datum_t *) hashtab_search(args->newp->p_users.table, args->oldp-> p_user_val_to_name[c->user - 1]); if (!usrdatum) { goto bad; } c->user = usrdatum->s.value; /* Convert the role. */ role = (role_datum_t *) hashtab_search(args->newp->p_roles.table, args->oldp-> p_role_val_to_name[c->role - 1]); if (!role) { goto bad; } c->role = role->s.value; /* Convert the type. */ typdatum = (type_datum_t *) hashtab_search(args->newp->p_types.table, args->oldp->p_type_val_to_name[c->type - 1]); if (!typdatum) { goto bad; } c->type = typdatum->s.value; rc = mls_convert_context(args->oldp, args->newp, c); if (rc) goto bad; /* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, c)) { rc = convert_context_handle_invalid_context(&oldc); if (rc) goto bad; } context_destroy(&oldc); return 0; bad: context_to_string(NULL, policydb, &oldc, &s, &len); context_destroy(&oldc); ERR(NULL, "invalidating context %s", s); free(s); return rc; } /* Reading from a policy "file". */ int hidden next_entry(void *buf, struct policy_file *fp, size_t bytes) { size_t nread; switch (fp->type) { case PF_USE_STDIO: nread = fread(buf, bytes, 1, fp->fp); if (nread != 1) return -1; break; case PF_USE_MEMORY: if (bytes > fp->len) return -1; memcpy(buf, fp->data, bytes); fp->data += bytes; fp->len -= bytes; break; default: return -1; } return 0; } size_t hidden put_entry(const void *ptr, size_t size, size_t n, struct policy_file *fp) { size_t bytes = size * n; switch (fp->type) { case PF_USE_STDIO: return fwrite(ptr, size, n, fp->fp); case PF_USE_MEMORY: if (bytes > fp->len) { errno = ENOSPC; return 0; } memcpy(fp->data, ptr, bytes); fp->data += bytes; fp->len -= bytes; return n; case PF_LEN: fp->len += bytes; return n; default: return 0; } return 0; } /* * Read a new set of configuration data from * a policy database binary representation file. * * Verify that each class that is defined under the * existing policy is still defined with the same * attributes in the new policy. * * Convert the context structures in the SID table to the * new representation and verify that all entries * in the SID table are valid under the new policy. * * Change the active policy database to use the new * configuration data. * * Reset the access vector cache. */ int hidden sepol_load_policy(void *data, size_t len) { policydb_t oldpolicydb, newpolicydb; sidtab_t oldsidtab, newsidtab; convert_context_args_t args; int rc = 0; struct policy_file file, *fp; policy_file_init(&file); file.type = PF_USE_MEMORY; file.data = data; file.len = len; fp = &file; if (policydb_init(&newpolicydb)) return -ENOMEM; if (policydb_read(&newpolicydb, fp, 1)) { policydb_destroy(&mypolicydb); return -EINVAL; } sepol_sidtab_init(&newsidtab); /* Verify that the existing classes did not change. */ if (hashtab_map (policydb->p_classes.table, validate_class, &newpolicydb)) { ERR(NULL, "the definition of an existing class changed"); rc = -EINVAL; goto err; } /* Clone the SID table. */ sepol_sidtab_shutdown(sidtab); if (sepol_sidtab_map(sidtab, clone_sid, &newsidtab)) { rc = -ENOMEM; goto err; } /* Convert the internal representations of contexts in the new SID table and remove invalid SIDs. */ args.oldp = policydb; args.newp = &newpolicydb; sepol_sidtab_map_remove_on_error(&newsidtab, convert_context, &args); /* Save the old policydb and SID table to free later. */ memcpy(&oldpolicydb, policydb, sizeof *policydb); sepol_sidtab_set(&oldsidtab, sidtab); /* Install the new policydb and SID table. */ memcpy(policydb, &newpolicydb, sizeof *policydb); sepol_sidtab_set(sidtab, &newsidtab); /* Free the old policydb and SID table. */ policydb_destroy(&oldpolicydb); sepol_sidtab_destroy(&oldsidtab); return 0; err: sepol_sidtab_destroy(&newsidtab); policydb_destroy(&newpolicydb); return rc; } /* * Return the SIDs to use for an unlabeled file system * that is being mounted from the device with the * the kdevname `name'. The `fs_sid' SID is returned for * the file system and the `file_sid' SID is returned * for all files within that file system. */ int hidden sepol_fs_sid(char *name, sepol_security_id_t * fs_sid, sepol_security_id_t * file_sid) { int rc = 0; ocontext_t *c; c = policydb->ocontexts[OCON_FS]; while (c) { if (strcmp(c->u.name, name) == 0) break; c = c->next; } if (c) { if (!c->sid[0] || !c->sid[1]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; rc = sepol_sidtab_context_to_sid(sidtab, &c->context[1], &c->sid[1]); if (rc) goto out; } *fs_sid = c->sid[0]; *file_sid = c->sid[1]; } else { *fs_sid = SECINITSID_FS; *file_sid = SECINITSID_FILE; } out: return rc; } /* * Return the SID of the port specified by * `domain', `type', `protocol', and `port'. */ int hidden sepol_port_sid(uint16_t domain __attribute__ ((unused)), uint16_t type __attribute__ ((unused)), uint8_t protocol, uint16_t port, sepol_security_id_t * out_sid) { ocontext_t *c; int rc = 0; c = policydb->ocontexts[OCON_PORT]; while (c) { if (c->u.port.protocol == protocol && c->u.port.low_port <= port && c->u.port.high_port >= port) break; c = c->next; } if (c) { if (!c->sid[0]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } *out_sid = c->sid[0]; } else { *out_sid = SECINITSID_PORT; } out: return rc; } /* * Return the SIDs to use for a network interface * with the name `name'. The `if_sid' SID is returned for * the interface and the `msg_sid' SID is returned as * the default SID for messages received on the * interface. */ int hidden sepol_netif_sid(char *name, sepol_security_id_t * if_sid, sepol_security_id_t * msg_sid) { int rc = 0; ocontext_t *c; c = policydb->ocontexts[OCON_NETIF]; while (c) { if (strcmp(name, c->u.name) == 0) break; c = c->next; } if (c) { if (!c->sid[0] || !c->sid[1]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; rc = sepol_sidtab_context_to_sid(sidtab, &c->context[1], &c->sid[1]); if (rc) goto out; } *if_sid = c->sid[0]; *msg_sid = c->sid[1]; } else { *if_sid = SECINITSID_NETIF; *msg_sid = SECINITSID_NETMSG; } out: return rc; } static int match_ipv6_addrmask(uint32_t * input, uint32_t * addr, uint32_t * mask) { int i, fail = 0; for (i = 0; i < 4; i++) if (addr[i] != (input[i] & mask[i])) { fail = 1; break; } return !fail; } /* * Return the SID of the node specified by the address * `addrp' where `addrlen' is the length of the address * in bytes and `domain' is the communications domain or * address family in which the address should be interpreted. */ int hidden sepol_node_sid(uint16_t domain, void *addrp, size_t addrlen, sepol_security_id_t * out_sid) { int rc = 0; ocontext_t *c; switch (domain) { case AF_INET:{ uint32_t addr; if (addrlen != sizeof(uint32_t)) { rc = -EINVAL; goto out; } addr = *((uint32_t *) addrp); c = policydb->ocontexts[OCON_NODE]; while (c) { if (c->u.node.addr == (addr & c->u.node.mask)) break; c = c->next; } break; } case AF_INET6: if (addrlen != sizeof(uint64_t) * 2) { rc = -EINVAL; goto out; } c = policydb->ocontexts[OCON_NODE6]; while (c) { if (match_ipv6_addrmask(addrp, c->u.node6.addr, c->u.node6.mask)) break; c = c->next; } break; default: *out_sid = SECINITSID_NODE; goto out; } if (c) { if (!c->sid[0]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } *out_sid = c->sid[0]; } else { *out_sid = SECINITSID_NODE; } out: return rc; } /* * Generate the set of SIDs for legal security contexts * for a given user that can be reached by `fromsid'. * Set `*sids' to point to a dynamically allocated * array containing the set of SIDs. Set `*nel' to the * number of elements in the array. */ #define SIDS_NEL 25 int hidden sepol_get_user_sids(sepol_security_id_t fromsid, char *username, sepol_security_id_t ** sids, uint32_t * nel) { context_struct_t *fromcon, usercon; sepol_security_id_t *mysids, *mysids2, sid; uint32_t mynel = 0, maxnel = SIDS_NEL; user_datum_t *user; role_datum_t *role; struct sepol_av_decision avd; int rc = 0; unsigned int i, j, reason; ebitmap_node_t *rnode, *tnode; fromcon = sepol_sidtab_search(sidtab, fromsid); if (!fromcon) { rc = -EINVAL; goto out; } user = (user_datum_t *) hashtab_search(policydb->p_users.table, username); if (!user) { rc = -EINVAL; goto out; } usercon.user = user->s.value; mysids = malloc(maxnel * sizeof(sepol_security_id_t)); if (!mysids) { rc = -ENOMEM; goto out; } memset(mysids, 0, maxnel * sizeof(sepol_security_id_t)); ebitmap_for_each_bit(&user->roles.roles, rnode, i) { if (!ebitmap_node_get_bit(rnode, i)) continue; role = policydb->role_val_to_struct[i]; usercon.role = i + 1; ebitmap_for_each_bit(&role->types.types, tnode, j) { if (!ebitmap_node_get_bit(tnode, j)) continue; usercon.type = j + 1; if (usercon.type == fromcon->type) continue; if (mls_setup_user_range (fromcon, user, &usercon, policydb->mls)) continue; rc = context_struct_compute_av(fromcon, &usercon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd, &reason, NULL, 0); if (rc || !(avd.allowed & PROCESS__TRANSITION)) continue; rc = sepol_sidtab_context_to_sid(sidtab, &usercon, &sid); if (rc) { free(mysids); goto out; } if (mynel < maxnel) { mysids[mynel++] = sid; } else { maxnel += SIDS_NEL; mysids2 = malloc(maxnel * sizeof(sepol_security_id_t)); if (!mysids2) { rc = -ENOMEM; free(mysids); goto out; } memset(mysids2, 0, maxnel * sizeof(sepol_security_id_t)); memcpy(mysids2, mysids, mynel * sizeof(sepol_security_id_t)); free(mysids); mysids = mysids2; mysids[mynel++] = sid; } } } *sids = mysids; *nel = mynel; out: return rc; } /* * Return the SID to use for a file in a filesystem * that cannot support a persistent label mapping or use another * fixed labeling behavior like transition SIDs or task SIDs. */ int hidden sepol_genfs_sid(const char *fstype, char *path, sepol_security_class_t sclass, sepol_security_id_t * sid) { size_t len; genfs_t *genfs; ocontext_t *c; int rc = 0, cmp = 0; for (genfs = policydb->genfs; genfs; genfs = genfs->next) { cmp = strcmp(fstype, genfs->fstype); if (cmp <= 0) break; } if (!genfs || cmp) { *sid = SECINITSID_UNLABELED; rc = -ENOENT; goto out; } for (c = genfs->head; c; c = c->next) { len = strlen(c->u.name); if ((!c->v.sclass || sclass == c->v.sclass) && (strncmp(c->u.name, path, len) == 0)) break; } if (!c) { *sid = SECINITSID_UNLABELED; rc = -ENOENT; goto out; } if (!c->sid[0]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } *sid = c->sid[0]; out: return rc; } int hidden sepol_fs_use(const char *fstype, unsigned int *behavior, sepol_security_id_t * sid) { int rc = 0; ocontext_t *c; c = policydb->ocontexts[OCON_FSUSE]; while (c) { if (strcmp(fstype, c->u.name) == 0) break; c = c->next; } if (c) { *behavior = c->v.behavior; if (!c->sid[0]) { rc = sepol_sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); if (rc) goto out; } *sid = c->sid[0]; } else { rc = sepol_genfs_sid(fstype, "/", SECCLASS_DIR, sid); if (rc) { *behavior = SECURITY_FS_USE_NONE; rc = 0; } else { *behavior = SECURITY_FS_USE_GENFS; } } out: return rc; } /* FLASK */ libsepol-2.2/src/sidtab.c000066400000000000000000000136501223423440700153750ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * Implementation of the SID table type. */ #include #include #include #include #include #include #define SIDTAB_HASH(sid) \ (sid & SIDTAB_HASH_MASK) #define INIT_SIDTAB_LOCK(s) #define SIDTAB_LOCK(s) #define SIDTAB_UNLOCK(s) int sepol_sidtab_init(sidtab_t * s) { int i; s->htable = malloc(sizeof(sidtab_ptr_t) * SIDTAB_SIZE); if (!s->htable) return -ENOMEM; for (i = 0; i < SIDTAB_SIZE; i++) s->htable[i] = (sidtab_ptr_t) NULL; s->nel = 0; s->next_sid = 1; s->shutdown = 0; INIT_SIDTAB_LOCK(s); return 0; } int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid, context_struct_t * context) { int hvalue; sidtab_node_t *prev, *cur, *newnode; if (!s || !s->htable) return -ENOMEM; hvalue = SIDTAB_HASH(sid); prev = NULL; cur = s->htable[hvalue]; while (cur != NULL && sid > cur->sid) { prev = cur; cur = cur->next; } if (cur && sid == cur->sid) { errno = EEXIST; return -EEXIST; } newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t)); if (newnode == NULL) return -ENOMEM; newnode->sid = sid; if (context_cpy(&newnode->context, context)) { free(newnode); return -ENOMEM; } if (prev) { newnode->next = prev->next; prev->next = newnode; } else { newnode->next = s->htable[hvalue]; s->htable[hvalue] = newnode; } s->nel++; if (sid >= s->next_sid) s->next_sid = sid + 1; return 0; } int sepol_sidtab_remove(sidtab_t * s, sepol_security_id_t sid) { int hvalue; sidtab_node_t *cur, *last; if (!s || !s->htable) return -ENOENT; hvalue = SIDTAB_HASH(sid); last = NULL; cur = s->htable[hvalue]; while (cur != NULL && sid > cur->sid) { last = cur; cur = cur->next; } if (cur == NULL || sid != cur->sid) return -ENOENT; if (last == NULL) s->htable[hvalue] = cur->next; else last->next = cur->next; context_destroy(&cur->context); free(cur); s->nel--; return 0; } context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid) { int hvalue; sidtab_node_t *cur; if (!s || !s->htable) return NULL; hvalue = SIDTAB_HASH(sid); cur = s->htable[hvalue]; while (cur != NULL && sid > cur->sid) cur = cur->next; if (cur == NULL || sid != cur->sid) { /* Remap invalid SIDs to the unlabeled SID. */ sid = SECINITSID_UNLABELED; hvalue = SIDTAB_HASH(sid); cur = s->htable[hvalue]; while (cur != NULL && sid > cur->sid) cur = cur->next; if (!cur || sid != cur->sid) return NULL; } return &cur->context; } int sepol_sidtab_map(sidtab_t * s, int (*apply) (sepol_security_id_t sid, context_struct_t * context, void *args), void *args) { int i, ret; sidtab_node_t *cur; if (!s || !s->htable) return 0; for (i = 0; i < SIDTAB_SIZE; i++) { cur = s->htable[i]; while (cur != NULL) { ret = apply(cur->sid, &cur->context, args); if (ret) return ret; cur = cur->next; } } return 0; } void sepol_sidtab_map_remove_on_error(sidtab_t * s, int (*apply) (sepol_security_id_t sid, context_struct_t * context, void *args), void *args) { int i, ret; sidtab_node_t *last, *cur, *temp; if (!s || !s->htable) return; for (i = 0; i < SIDTAB_SIZE; i++) { last = NULL; cur = s->htable[i]; while (cur != NULL) { ret = apply(cur->sid, &cur->context, args); if (ret) { if (last) { last->next = cur->next; } else { s->htable[i] = cur->next; } temp = cur; cur = cur->next; context_destroy(&temp->context); free(temp); s->nel--; } else { last = cur; cur = cur->next; } } } return; } static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s, context_struct_t * context) { int i; sidtab_node_t *cur; for (i = 0; i < SIDTAB_SIZE; i++) { cur = s->htable[i]; while (cur != NULL) { if (context_cmp(&cur->context, context)) return cur->sid; cur = cur->next; } } return 0; } int sepol_sidtab_context_to_sid(sidtab_t * s, context_struct_t * context, sepol_security_id_t * out_sid) { sepol_security_id_t sid; int ret = 0; *out_sid = SEPOL_SECSID_NULL; sid = sepol_sidtab_search_context(s, context); if (!sid) { SIDTAB_LOCK(s); /* Rescan now that we hold the lock. */ sid = sepol_sidtab_search_context(s, context); if (sid) goto unlock_out; /* No SID exists for the context. Allocate a new one. */ if (s->next_sid == UINT_MAX || s->shutdown) { ret = -ENOMEM; goto unlock_out; } sid = s->next_sid++; ret = sepol_sidtab_insert(s, sid, context); if (ret) s->next_sid--; unlock_out: SIDTAB_UNLOCK(s); } if (ret) return ret; *out_sid = sid; return 0; } void sepol_sidtab_hash_eval(sidtab_t * h, char *tag) { int i, chain_len, slots_used, max_chain_len; sidtab_node_t *cur; slots_used = 0; max_chain_len = 0; for (i = 0; i < SIDTAB_SIZE; i++) { cur = h->htable[i]; if (cur) { slots_used++; chain_len = 0; while (cur) { chain_len++; cur = cur->next; } if (chain_len > max_chain_len) max_chain_len = chain_len; } } printf ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len); } void sepol_sidtab_destroy(sidtab_t * s) { int i; sidtab_ptr_t cur, temp; if (!s || !s->htable) return; for (i = 0; i < SIDTAB_SIZE; i++) { cur = s->htable[i]; while (cur != NULL) { temp = cur; cur = cur->next; context_destroy(&temp->context); free(temp); } s->htable[i] = NULL; } free(s->htable); s->htable = NULL; s->nel = 0; s->next_sid = 1; } void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src) { SIDTAB_LOCK(src); dst->htable = src->htable; dst->nel = src->nel; dst->next_sid = src->next_sid; dst->shutdown = 0; SIDTAB_UNLOCK(src); } void sepol_sidtab_shutdown(sidtab_t * s) { SIDTAB_LOCK(s); s->shutdown = 1; SIDTAB_UNLOCK(s); } /* FLASK */ libsepol-2.2/src/symtab.c000066400000000000000000000020021223423440700154130ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* FLASK */ /* * Implementation of the symbol table type. */ #include #include #include static unsigned int symhash(hashtab_t h, hashtab_key_t key) { char *p, *keyp; size_t size; unsigned int val; val = 0; keyp = (char *)key; size = strlen(keyp); for (p = keyp; ((size_t) (p - keyp)) < size; p++) val = (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); return val & (h->size - 1); } static int symcmp(hashtab_t h __attribute__ ((unused)), hashtab_key_t key1, hashtab_key_t key2) { char *keyp1, *keyp2; keyp1 = (char *)key1; keyp2 = (char *)key2; return strcmp(keyp1, keyp2); } int symtab_init(symtab_t * s, unsigned int size) { s->table = hashtab_create(symhash, symcmp, size); if (!s->table) return -1; s->nprim = 0; return 0; } void symtab_destroy(symtab_t * s) { if (!s) return; if (s->table) hashtab_destroy(s->table); return; } /* FLASK */ libsepol-2.2/src/user_internal.h000066400000000000000000000011451223423440700170020ustar00rootroot00000000000000#ifndef _SEPOL_USER_INTERNAL_H_ #define _SEPOL_USER_INTERNAL_H_ #include #include #include "dso.h" hidden_proto(sepol_user_add_role) hidden_proto(sepol_user_create) hidden_proto(sepol_user_free) hidden_proto(sepol_user_get_mlslevel) hidden_proto(sepol_user_get_mlsrange) hidden_proto(sepol_user_get_roles) hidden_proto(sepol_user_has_role) hidden_proto(sepol_user_key_create) hidden_proto(sepol_user_key_unpack) hidden_proto(sepol_user_set_mlslevel) hidden_proto(sepol_user_set_mlsrange) hidden_proto(sepol_user_set_name) #endif libsepol-2.2/src/user_record.c000066400000000000000000000164661223423440700164530ustar00rootroot00000000000000#include #include #include #include "user_internal.h" #include "debug.h" struct sepol_user { /* This user's name */ char *name; /* This user's mls level (only required for mls) */ char *mls_level; /* This user's mls range (only required for mls) */ char *mls_range; /* The role array */ char **roles; /* The number of roles */ unsigned int num_roles; }; struct sepol_user_key { /* This user's name */ const char *name; }; int sepol_user_key_create(sepol_handle_t * handle, const char *name, sepol_user_key_t ** key_ptr) { sepol_user_key_t *tmp_key = (sepol_user_key_t *) malloc(sizeof(sepol_user_key_t)); if (!tmp_key) { ERR(handle, "out of memory, " "could not create selinux user key"); return STATUS_ERR; } tmp_key->name = name; *key_ptr = tmp_key; return STATUS_SUCCESS; } hidden_def(sepol_user_key_create) void sepol_user_key_unpack(const sepol_user_key_t * key, const char **name) { *name = key->name; } hidden_def(sepol_user_key_unpack) int sepol_user_key_extract(sepol_handle_t * handle, const sepol_user_t * user, sepol_user_key_t ** key_ptr) { if (sepol_user_key_create(handle, user->name, key_ptr) < 0) { ERR(handle, "could not extract key from user %s", user->name); return STATUS_ERR; } return STATUS_SUCCESS; } void sepol_user_key_free(sepol_user_key_t * key) { free(key); } int sepol_user_compare(const sepol_user_t * user, const sepol_user_key_t * key) { return strcmp(user->name, key->name); } int sepol_user_compare2(const sepol_user_t * user, const sepol_user_t * user2) { return strcmp(user->name, user2->name); } /* Name */ const char *sepol_user_get_name(const sepol_user_t * user) { return user->name; } int sepol_user_set_name(sepol_handle_t * handle, sepol_user_t * user, const char *name) { char *tmp_name = strdup(name); if (!tmp_name) { ERR(handle, "out of memory, could not set name"); return STATUS_ERR; } free(user->name); user->name = tmp_name; return STATUS_SUCCESS; } hidden_def(sepol_user_set_name) /* MLS */ const char *sepol_user_get_mlslevel(const sepol_user_t * user) { return user->mls_level; } hidden_def(sepol_user_get_mlslevel) int sepol_user_set_mlslevel(sepol_handle_t * handle, sepol_user_t * user, const char *mls_level) { char *tmp_mls_level = strdup(mls_level); if (!tmp_mls_level) { ERR(handle, "out of memory, " "could not set MLS default level"); return STATUS_ERR; } free(user->mls_level); user->mls_level = tmp_mls_level; return STATUS_SUCCESS; } hidden_def(sepol_user_set_mlslevel) const char *sepol_user_get_mlsrange(const sepol_user_t * user) { return user->mls_range; } hidden_def(sepol_user_get_mlsrange) int sepol_user_set_mlsrange(sepol_handle_t * handle, sepol_user_t * user, const char *mls_range) { char *tmp_mls_range = strdup(mls_range); if (!tmp_mls_range) { ERR(handle, "out of memory, " "could not set MLS allowed range"); return STATUS_ERR; } free(user->mls_range); user->mls_range = tmp_mls_range; return STATUS_SUCCESS; } hidden_def(sepol_user_set_mlsrange) /* Roles */ int sepol_user_get_num_roles(const sepol_user_t * user) { return user->num_roles; } int sepol_user_add_role(sepol_handle_t * handle, sepol_user_t * user, const char *role) { char *role_cp; char **roles_realloc; if (sepol_user_has_role(user, role)) return STATUS_SUCCESS; role_cp = strdup(role); roles_realloc = realloc(user->roles, sizeof(char *) * (user->num_roles + 1)); if (!role_cp || !roles_realloc) goto omem; user->num_roles++; user->roles = roles_realloc; user->roles[user->num_roles - 1] = role_cp; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not add role %s", role); free(role_cp); free(roles_realloc); return STATUS_ERR; } hidden_def(sepol_user_add_role) int sepol_user_has_role(const sepol_user_t * user, const char *role) { unsigned int i; for (i = 0; i < user->num_roles; i++) if (!strcmp(user->roles[i], role)) return 1; return 0; } hidden_def(sepol_user_has_role) int sepol_user_set_roles(sepol_handle_t * handle, sepol_user_t * user, const char **roles_arr, unsigned int num_roles) { unsigned int i; char **tmp_roles = NULL; if (num_roles > 0) { /* First, make a copy */ tmp_roles = (char **)calloc(1, sizeof(char *) * num_roles); if (!tmp_roles) goto omem; for (i = 0; i < num_roles; i++) { tmp_roles[i] = strdup(roles_arr[i]); if (!tmp_roles[i]) goto omem; } } /* Apply other changes */ for (i = 0; i < user->num_roles; i++) free(user->roles[i]); free(user->roles); user->roles = tmp_roles; user->num_roles = num_roles; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not allocate roles array for" "user %s", user->name); if (tmp_roles) { for (i = 0; i < num_roles; i++) { if (!tmp_roles[i]) break; free(tmp_roles[i]); } } free(tmp_roles); return STATUS_ERR; } int sepol_user_get_roles(sepol_handle_t * handle, const sepol_user_t * user, const char ***roles_arr, unsigned int *num_roles) { unsigned int i; const char **tmp_roles = (const char **)malloc(sizeof(char *) * user->num_roles); if (!tmp_roles) goto omem; for (i = 0; i < user->num_roles; i++) tmp_roles[i] = user->roles[i]; *roles_arr = tmp_roles; *num_roles = user->num_roles; return STATUS_SUCCESS; omem: ERR(handle, "out of memory, could not " "allocate roles array for user %s", user->name); free(tmp_roles); return STATUS_ERR; } hidden_def(sepol_user_get_roles) void sepol_user_del_role(sepol_user_t * user, const char *role) { unsigned int i; for (i = 0; i < user->num_roles; i++) { if (!strcmp(user->roles[i], role)) { free(user->roles[i]); user->roles[i] = NULL; user->roles[i] = user->roles[user->num_roles - 1]; user->num_roles--; } } } /* Create */ int sepol_user_create(sepol_handle_t * handle, sepol_user_t ** user_ptr) { sepol_user_t *user = (sepol_user_t *) malloc(sizeof(sepol_user_t)); if (!user) { ERR(handle, "out of memory, " "could not create selinux user record"); return STATUS_ERR; } user->roles = NULL; user->num_roles = 0; user->name = NULL; user->mls_level = NULL; user->mls_range = NULL; *user_ptr = user; return STATUS_SUCCESS; } hidden_def(sepol_user_create) /* Deep copy clone */ int sepol_user_clone(sepol_handle_t * handle, const sepol_user_t * user, sepol_user_t ** user_ptr) { sepol_user_t *new_user = NULL; unsigned int i; if (sepol_user_create(handle, &new_user) < 0) goto err; if (sepol_user_set_name(handle, new_user, user->name) < 0) goto err; for (i = 0; i < user->num_roles; i++) { if (sepol_user_add_role(handle, new_user, user->roles[i]) < 0) goto err; } if (user->mls_level && (sepol_user_set_mlslevel(handle, new_user, user->mls_level) < 0)) goto err; if (user->mls_range && (sepol_user_set_mlsrange(handle, new_user, user->mls_range) < 0)) goto err; *user_ptr = new_user; return STATUS_SUCCESS; err: ERR(handle, "could not clone selinux user record"); sepol_user_free(new_user); return STATUS_ERR; } /* Destroy */ void sepol_user_free(sepol_user_t * user) { unsigned int i; if (!user) return; free(user->name); for (i = 0; i < user->num_roles; i++) free(user->roles[i]); free(user->roles); free(user->mls_level); free(user->mls_range); free(user); } hidden_def(sepol_user_free) libsepol-2.2/src/users.c000066400000000000000000000212021223423440700152600ustar00rootroot00000000000000#include #include #include #include "private.h" #include "debug.h" #include "handle.h" #include #include #include #include "user_internal.h" #include "mls.h" static int user_to_record(sepol_handle_t * handle, const policydb_t * policydb, int user_idx, sepol_user_t ** record) { const char *name = policydb->p_user_val_to_name[user_idx]; user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx]; ebitmap_t *roles = &(usrdatum->roles.roles); ebitmap_node_t *rnode; unsigned bit; sepol_user_t *tmp_record = NULL; if (sepol_user_create(handle, &tmp_record) < 0) goto err; if (sepol_user_set_name(handle, tmp_record, name) < 0) goto err; /* Extract roles */ ebitmap_for_each_bit(roles, rnode, bit) { if (ebitmap_node_get_bit(rnode, bit)) { char *role = policydb->p_role_val_to_name[bit]; if (sepol_user_add_role(handle, tmp_record, role) < 0) goto err; } } /* Extract MLS info */ if (policydb->mls) { context_struct_t context; char *str; context_init(&context); if (mls_level_cpy(&context.range.level[0], &usrdatum->exp_dfltlevel) < 0) { ERR(handle, "could not copy MLS level"); context_destroy(&context); goto err; } if (mls_level_cpy(&context.range.level[1], &usrdatum->exp_dfltlevel) < 0) { ERR(handle, "could not copy MLS level"); context_destroy(&context); goto err; } if (mls_to_string(handle, policydb, &context, &str) < 0) { context_destroy(&context); goto err; } context_destroy(&context); if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) { free(str); goto err; } free(str); context_init(&context); if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) { ERR(handle, "could not copy MLS range"); context_destroy(&context); goto err; } if (mls_to_string(handle, policydb, &context, &str) < 0) { context_destroy(&context); goto err; } context_destroy(&context); if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) { free(str); goto err; } free(str); } *record = tmp_record; return STATUS_SUCCESS; err: /* FIXME: handle error */ sepol_user_free(tmp_record); return STATUS_ERR; } int sepol_user_modify(sepol_handle_t * handle, sepol_policydb_t * p, const sepol_user_key_t * key, const sepol_user_t * user) { policydb_t *policydb = &p->p; /* For user data */ const char *cname, *cmls_level, *cmls_range; char *name = NULL; const char **roles = NULL; unsigned int num_roles = 0; /* Low-level representation */ user_datum_t *usrdatum = NULL; role_datum_t *roldatum; unsigned int i; context_struct_t context; unsigned bit; int new = 0; ebitmap_node_t *rnode; /* First, extract all the data */ sepol_user_key_unpack(key, &cname); cmls_level = sepol_user_get_mlslevel(user); cmls_range = sepol_user_get_mlsrange(user); /* Make sure that worked properly */ if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0) goto err; /* Now, see if a user exists */ usrdatum = hashtab_search(policydb->p_users.table, (const hashtab_key_t)cname); /* If it does, we will modify it */ if (usrdatum) { int value_cp = usrdatum->s.value; user_datum_destroy(usrdatum); user_datum_init(usrdatum); usrdatum->s.value = value_cp; /* Otherwise, create a new one */ } else { usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t)); if (!usrdatum) goto omem; user_datum_init(usrdatum); new = 1; } /* For every role */ for (i = 0; i < num_roles; i++) { /* Search for the role */ roldatum = hashtab_search(policydb->p_roles.table, (const hashtab_key_t)roles[i]); if (!roldatum) { ERR(handle, "undefined role %s for user %s", roles[i], cname); goto err; } /* Set the role and every role it dominates */ ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) { if (ebitmap_node_get_bit(rnode, bit)) { if (ebitmap_set_bit (&(usrdatum->roles.roles), bit, 1)) goto omem; } } } /* For MLS systems */ if (policydb->mls) { /* MLS level */ if (cmls_level == NULL) { ERR(handle, "MLS is enabled, but no MLS " "default level was defined for user %s", cname); goto err; } context_init(&context); if (mls_from_string(handle, policydb, cmls_level, &context) < 0) { context_destroy(&context); goto err; } if (mls_level_cpy(&usrdatum->exp_dfltlevel, &context.range.level[0]) < 0) { ERR(handle, "could not copy MLS level %s", cmls_level); context_destroy(&context); goto err; } context_destroy(&context); /* MLS range */ if (cmls_range == NULL) { ERR(handle, "MLS is enabled, but no MLS" "range was defined for user %s", cname); goto err; } context_init(&context); if (mls_from_string(handle, policydb, cmls_range, &context) < 0) { context_destroy(&context); goto err; } if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) { ERR(handle, "could not copy MLS range %s", cmls_range); context_destroy(&context); goto err; } context_destroy(&context); } else if (cmls_level != NULL || cmls_range != NULL) { ERR(handle, "MLS is disabled, but MLS level/range " "was found for user %s", cname); goto err; } /* If there are no errors, and this is a new user, add the user to policy */ if (new) { void *tmp_ptr; /* Ensure reverse lookup array has enough space */ tmp_ptr = realloc(policydb->user_val_to_struct, (policydb->p_users.nprim + 1) * sizeof(user_datum_t *)); if (!tmp_ptr) goto omem; policydb->user_val_to_struct = tmp_ptr; tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS], (policydb->p_users.nprim + 1) * sizeof(char *)); if (!tmp_ptr) goto omem; policydb->sym_val_to_name[SYM_USERS] = tmp_ptr; /* Need to copy the user name */ name = strdup(cname); if (!name) goto omem; /* Store user */ usrdatum->s.value = ++policydb->p_users.nprim; if (hashtab_insert(policydb->p_users.table, name, (hashtab_datum_t) usrdatum) < 0) goto omem; /* Set up reverse entry */ policydb->p_user_val_to_name[usrdatum->s.value - 1] = name; policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum; name = NULL; /* Expand roles */ if (role_set_expand(&usrdatum->roles, &usrdatum->cache, policydb, NULL, NULL)) { ERR(handle, "unable to expand role set"); goto err; } } free(roles); return STATUS_SUCCESS; omem: ERR(handle, "out of memory"); err: ERR(handle, "could not load %s into policy", name); free(name); free(roles); if (new && usrdatum) { role_set_destroy(&usrdatum->roles); free(usrdatum); } return STATUS_ERR; } int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, const sepol_user_key_t * key, int *response) { const policydb_t *policydb = &p->p; const char *cname; sepol_user_key_unpack(key, &cname); *response = (hashtab_search(policydb->p_users.table, (const hashtab_key_t)cname) != NULL); handle = NULL; return STATUS_SUCCESS; } int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)), const sepol_policydb_t * p, unsigned int *response) { const policydb_t *policydb = &p->p; *response = policydb->p_users.nprim; handle = NULL; return STATUS_SUCCESS; } int sepol_user_query(sepol_handle_t * handle, const sepol_policydb_t * p, const sepol_user_key_t * key, sepol_user_t ** response) { const policydb_t *policydb = &p->p; user_datum_t *usrdatum = NULL; const char *cname; sepol_user_key_unpack(key, &cname); usrdatum = hashtab_search(policydb->p_users.table, (const hashtab_key_t)cname); if (!usrdatum) { *response = NULL; return STATUS_SUCCESS; } if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) < 0) goto err; return STATUS_SUCCESS; err: ERR(handle, "could not query user %s", cname); return STATUS_ERR; } int sepol_user_iterate(sepol_handle_t * handle, const sepol_policydb_t * p, int (*fn) (const sepol_user_t * user, void *fn_arg), void *arg) { const policydb_t *policydb = &p->p; unsigned int nusers = policydb->p_users.nprim; sepol_user_t *user = NULL; unsigned int i; /* For each user */ for (i = 0; i < nusers; i++) { int status; if (user_to_record(handle, policydb, i, &user) < 0) goto err; /* Invoke handler */ status = fn(user, arg); if (status < 0) goto err; sepol_user_free(user); user = NULL; /* Handler requested exit */ if (status > 0) break; } return STATUS_SUCCESS; err: ERR(handle, "could not iterate over users"); sepol_user_free(user); return STATUS_ERR; } libsepol-2.2/src/util.c000066400000000000000000000060751223423440700151070ustar00rootroot00000000000000/* Authors: Joshua Brindle * Jason Tang * * Copyright (C) 2005-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 #include #include #include #include struct val_to_name { unsigned int val; char *name; }; /* Add an unsigned integer to a dynamically reallocated array. *cnt * is a reference pointer to the number of values already within array * *a; it will be incremented upon successfully appending i. If *a is * NULL then this function will create a new array (*cnt is reset to * 0). Return 0 on success, -1 on out of memory. */ int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a) { if (cnt == NULL || a == NULL) return -1; /* FIX ME: This is not very elegant! We use an array that we * grow as new uint32_t are added to an array. But rather * than be smart about it, for now we realloc() the array each * time a new uint32_t is added! */ if (*a != NULL) *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t)); else { /* empty list */ *cnt = 0; *a = (uint32_t *) malloc(sizeof(uint32_t)); } if (*a == NULL) { return -1; } (*a)[*cnt] = i; (*cnt)++; return 0; } static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data) { struct val_to_name *v = data; perm_datum_t *perdatum; perdatum = (perm_datum_t *) datum; if (v->val == perdatum->s.value) { v->name = key; return 1; } return 0; } char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass, sepol_access_vector_t av) { struct val_to_name v; static char avbuf[1024]; class_datum_t *cladatum; char *perm = NULL, *p; unsigned int i; int rc; int avlen = 0, len; cladatum = policydbp->class_val_to_struct[tclass - 1]; p = avbuf; for (i = 0; i < cladatum->permissions.nprim; i++) { if (av & (1 << i)) { v.val = i + 1; rc = hashtab_map(cladatum->permissions.table, perm_name, &v); if (!rc && cladatum->comdatum) { rc = hashtab_map(cladatum->comdatum-> permissions.table, perm_name, &v); } if (rc) perm = v.name; if (perm) { len = snprintf(p, sizeof(avbuf) - avlen, " %s", perm); if (len < 0 || (size_t) len >= (sizeof(avbuf) - avlen)) return NULL; p += len; avlen += len; } } } return avbuf; } libsepol-2.2/src/write.c000066400000000000000000001537171223423440700152720ustar00rootroot00000000000000 /* Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Updated: Frank Mayer and Karl MacMillan * * Added conditional policy language extensions * * Updated: Joshua Brindle and Jason Tang * * Module writing support * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003-2005 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 #include #include #include #include #include #include #include #include "debug.h" #include "private.h" #include "mls.h" struct policy_data { struct policy_file *fp; struct policydb *p; }; static int avrule_write_list(avrule_t * avrules, struct policy_file *fp); static int ebitmap_write(ebitmap_t * e, struct policy_file *fp) { ebitmap_node_t *n; uint32_t buf[32], bit, count; uint64_t map; size_t items; buf[0] = cpu_to_le32(MAPSIZE); buf[1] = cpu_to_le32(e->highbit); count = 0; for (n = e->node; n; n = n->next) count++; buf[2] = cpu_to_le32(count); items = put_entry(buf, sizeof(uint32_t), 3, fp); if (items != 3) return POLICYDB_ERROR; for (n = e->node; n; n = n->next) { bit = cpu_to_le32(n->startbit); items = put_entry(&bit, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; map = cpu_to_le64(n->map); items = put_entry(&map, sizeof(uint64_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /* Ordering of datums in the original avtab format in the policy file. */ static uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, AVTAB_MEMBER }; static int avtab_write_item(policydb_t * p, avtab_ptr_t cur, struct policy_file *fp, unsigned merge, unsigned commit, uint32_t * nel) { avtab_ptr_t node; uint16_t buf16[4]; uint32_t buf32[10], lookup, val; size_t items, items2; unsigned set; unsigned int oldvers = (p->policy_type == POLICY_KERN && p->policyvers < POLICYDB_VERSION_AVTAB); unsigned int i; if (oldvers) { /* Generate the old avtab format. Requires merging similar entries if uncond avtab. */ if (merge) { if (cur->merged) return POLICYDB_SUCCESS; /* already merged by prior merge */ } items = 1; /* item 0 is used for the item count */ val = cur->key.source_type; buf32[items++] = cpu_to_le32(val); val = cur->key.target_type; buf32[items++] = cpu_to_le32(val); val = cur->key.target_class; buf32[items++] = cpu_to_le32(val); val = cur->key.specified & ~AVTAB_ENABLED; if (cur->key.specified & AVTAB_ENABLED) val |= AVTAB_ENABLED_OLD; set = 1; if (merge) { /* Merge specifier values for all similar (av or type) entries that have the same key. */ if (val & AVTAB_AV) lookup = AVTAB_AV; else if (val & AVTAB_TYPE) lookup = AVTAB_TYPE; else return POLICYDB_ERROR; for (node = avtab_search_node_next(cur, lookup); node; node = avtab_search_node_next(node, lookup)) { val |= (node->key.specified & ~AVTAB_ENABLED); set++; if (node->key.specified & AVTAB_ENABLED) val |= AVTAB_ENABLED_OLD; } } if (!(val & (AVTAB_AV | AVTAB_TYPE))) { ERR(fp->handle, "null entry"); return POLICYDB_ERROR; } if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { ERR(fp->handle, "entry has both access " "vectors and types"); return POLICYDB_ERROR; } buf32[items++] = cpu_to_le32(val); if (merge) { /* Include datums for all similar (av or type) entries that have the same key. */ for (i = 0; i < (sizeof(spec_order) / sizeof(spec_order[0])); i++) { if (val & spec_order[i]) { if (cur->key.specified & spec_order[i]) node = cur; else { node = avtab_search_node_next(cur, spec_order [i]); if (nel) (*nel)--; /* one less node */ } if (!node) { ERR(fp->handle, "missing node"); return POLICYDB_ERROR; } buf32[items++] = cpu_to_le32(node->datum.data); set--; node->merged = 1; } } } else { buf32[items++] = cpu_to_le32(cur->datum.data); cur->merged = 1; set--; } if (set) { ERR(fp->handle, "data count wrong"); return POLICYDB_ERROR; } buf32[0] = cpu_to_le32(items - 1); if (commit) { /* Commit this item to the policy file. */ items2 = put_entry(buf32, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /* Generate the new avtab format. */ buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); buf16[2] = cpu_to_le16(cur->key.target_class); buf16[3] = cpu_to_le16(cur->key.specified); items = put_entry(buf16, sizeof(uint16_t), 4, fp); if (items != 4) return POLICYDB_ERROR; buf32[0] = cpu_to_le32(cur->datum.data); items = put_entry(buf32, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static inline void avtab_reset_merged(avtab_t * a) { unsigned int i; avtab_ptr_t cur; for (i = 0; i < a->nslot; i++) { for (cur = a->htable[i]; cur; cur = cur->next) cur->merged = 0; } } static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp) { unsigned int i; int rc; avtab_t expa; avtab_ptr_t cur; uint32_t nel; size_t items; unsigned int oldvers = (p->policy_type == POLICY_KERN && p->policyvers < POLICYDB_VERSION_AVTAB); if (oldvers) { /* Old avtab format. First, we need to expand attributes. Then, we need to merge similar entries, so we need to track merged nodes and compute the final nel. */ if (avtab_init(&expa)) return POLICYDB_ERROR; if (expand_avtab(p, a, &expa)) { rc = -1; goto out; } a = &expa; avtab_reset_merged(a); nel = a->nel; } else { /* New avtab format. nel is good to go. */ nel = cpu_to_le32(a->nel); items = put_entry(&nel, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } for (i = 0; i < a->nslot; i++) { for (cur = a->htable[i]; cur; cur = cur->next) { /* If old format, compute final nel. If new format, write out the items. */ if (avtab_write_item(p, cur, fp, 1, !oldvers, &nel)) { rc = -1; goto out; } } } if (oldvers) { /* Old avtab format. Write the computed nel value, then write the items. */ nel = cpu_to_le32(nel); items = put_entry(&nel, sizeof(uint32_t), 1, fp); if (items != 1) { rc = -1; goto out; } avtab_reset_merged(a); for (i = 0; i < a->nslot; i++) { for (cur = a->htable[i]; cur; cur = cur->next) { if (avtab_write_item(p, cur, fp, 1, 1, NULL)) { rc = -1; goto out; } } } } rc = 0; out: if (oldvers) avtab_destroy(&expa); return rc; } /* * Write a semantic MLS level structure to a policydb binary * representation file. */ static int mls_write_semantic_level_helper(mls_semantic_level_t * l, struct policy_file *fp) { uint32_t buf[2], ncat = 0; size_t items; mls_semantic_cat_t *cat; for (cat = l->cat; cat; cat = cat->next) ncat++; buf[0] = cpu_to_le32(l->sens); buf[1] = cpu_to_le32(ncat); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; for (cat = l->cat; cat; cat = cat->next) { buf[0] = cpu_to_le32(cat->low); buf[1] = cpu_to_le32(cat->high); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /* * Read a semantic MLS range structure to a policydb binary * representation file. */ static int mls_write_semantic_range_helper(mls_semantic_range_t * r, struct policy_file *fp) { int rc; rc = mls_write_semantic_level_helper(&r->level[0], fp); if (rc) return rc; rc = mls_write_semantic_level_helper(&r->level[1], fp); return rc; } /* * Write a MLS level structure to a policydb binary * representation file. */ static int mls_write_level(mls_level_t * l, struct policy_file *fp) { uint32_t sens; size_t items; sens = cpu_to_le32(l->sens); items = put_entry(&sens, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (ebitmap_write(&l->cat, fp)) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } /* * Write a MLS range structure to a policydb binary * representation file. */ static int mls_write_range_helper(mls_range_t * r, struct policy_file *fp) { uint32_t buf[3]; size_t items, items2; int eq; eq = mls_level_eq(&r->level[1], &r->level[0]); items = 1; /* item 0 is used for the item count */ buf[items++] = cpu_to_le32(r->level[0].sens); if (!eq) buf[items++] = cpu_to_le32(r->level[1].sens); buf[0] = cpu_to_le32(items - 1); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; if (ebitmap_write(&r->level[0].cat, fp)) return POLICYDB_ERROR; if (!eq) if (ebitmap_write(&r->level[1].cat, fp)) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { level_datum_t *levdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; levdatum = (level_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(levdatum->isalias); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (mls_write_level(levdatum->level, fp)) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { cat_datum_t *catdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; catdatum = (cat_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(catdatum->s.value); buf[items++] = cpu_to_le32(catdatum->isalias); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int role_trans_write(policydb_t *p, struct policy_file *fp) { role_trans_t *r = p->role_tr; role_trans_t *tr; uint32_t buf[3]; size_t nel, items; int new_roletr = (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_ROLETRANS); int warning_issued = 0; nel = 0; for (tr = r; tr; tr = tr->next) if(new_roletr || tr->tclass == SECCLASS_PROCESS) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (tr = r; tr; tr = tr->next) { if (!new_roletr && tr->tclass != SECCLASS_PROCESS) { if (!warning_issued) WARN(fp->handle, "Discarding role_transition " "rules for security classes other than " "\"process\""); warning_issued = 1; continue; } buf[0] = cpu_to_le32(tr->role); buf[1] = cpu_to_le32(tr->type); buf[2] = cpu_to_le32(tr->new_role); items = put_entry(buf, sizeof(uint32_t), 3, fp); if (items != 3) return POLICYDB_ERROR; if (new_roletr) { buf[0] = cpu_to_le32(tr->tclass); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } } return POLICYDB_SUCCESS; } static int role_allow_write(role_allow_t * r, struct policy_file *fp) { role_allow_t *ra; uint32_t buf[2]; size_t nel, items; nel = 0; for (ra = r; ra; ra = ra->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (ra = r; ra; ra = ra->next) { buf[0] = cpu_to_le32(ra->role); buf[1] = cpu_to_le32(ra->new_role); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int filename_trans_write(filename_trans_t * r, struct policy_file *fp) { filename_trans_t *ft; uint32_t buf[4]; size_t nel, items, len; nel = 0; for (ft = r; ft; ft = ft->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (ft = r; ft; ft = ft->next) { len = strlen(ft->name); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(ft->name, sizeof(char), len, fp); if (items != len) return POLICYDB_ERROR; buf[0] = cpu_to_le32(ft->stype); buf[1] = cpu_to_le32(ft->ttype); buf[2] = cpu_to_le32(ft->tclass); buf[3] = cpu_to_le32(ft->otype); items = put_entry(buf, sizeof(uint32_t), 4, fp); if (items != 4) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int role_set_write(role_set_t * x, struct policy_file *fp) { size_t items; uint32_t buf[1]; if (ebitmap_write(&x->roles, fp)) return POLICYDB_ERROR; buf[0] = cpu_to_le32(x->flags); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int type_set_write(type_set_t * x, struct policy_file *fp) { size_t items; uint32_t buf[1]; if (ebitmap_write(&x->types, fp)) return POLICYDB_ERROR; if (ebitmap_write(&x->negset, fp)) return POLICYDB_ERROR; buf[0] = cpu_to_le32(x->flags); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { cond_bool_datum_t *booldatum; uint32_t buf[3], len; unsigned int items, items2; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; struct policydb *p = pd->p; booldatum = (cond_bool_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(booldatum->s.value); buf[items++] = cpu_to_le32(booldatum->state); buf[items++] = cpu_to_le32(len); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { buf[0] = cpu_to_le32(booldatum->flags); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /* * cond_write_cond_av_list doesn't write out the av_list nodes. * Instead it writes out the key/value pairs from the avtab. This * is necessary because there is no way to uniquely identifying rules * in the avtab so it is not possible to associate individual rules * in the avtab with a conditional without saving them as part of * the conditional. This means that the avtab with the conditional * rules will not be saved but will be rebuilt on policy load. */ static int cond_write_av_list(policydb_t * p, cond_av_list_t * list, struct policy_file *fp) { uint32_t buf[4]; cond_av_list_t *cur_list, *new_list = NULL; avtab_t expa; uint32_t len, items; unsigned int oldvers = (p->policy_type == POLICY_KERN && p->policyvers < POLICYDB_VERSION_AVTAB); int rc = -1; if (oldvers) { if (avtab_init(&expa)) return POLICYDB_ERROR; if (expand_cond_av_list(p, list, &new_list, &expa)) goto out; list = new_list; } len = 0; for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { if (cur_list->node->parse_context) len++; } buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) goto out; if (len == 0) { rc = 0; goto out; } for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { if (cur_list->node->parse_context) if (avtab_write_item(p, cur_list->node, fp, 0, 1, NULL)) goto out; } rc = 0; out: if (oldvers) { cond_av_list_destroy(new_list); avtab_destroy(&expa); } return rc; } static int cond_write_node(policydb_t * p, cond_node_t * node, struct policy_file *fp) { cond_expr_t *cur_expr; uint32_t buf[2]; uint32_t items, items2, len; buf[0] = cpu_to_le32(node->cur_state); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; /* expr */ len = 0; for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) len++; buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) { items = 0; buf[items++] = cpu_to_le32(cur_expr->expr_type); buf[items++] = cpu_to_le32(cur_expr->bool); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; } if (p->policy_type == POLICY_KERN) { if (cond_write_av_list(p, node->true_list, fp) != 0) return POLICYDB_ERROR; if (cond_write_av_list(p, node->false_list, fp) != 0) return POLICYDB_ERROR; } else { if (avrule_write_list(node->avtrue_list, fp)) return POLICYDB_ERROR; if (avrule_write_list(node->avfalse_list, fp)) return POLICYDB_ERROR; } if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { buf[0] = cpu_to_le32(node->flags); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int cond_write_list(policydb_t * p, cond_list_t * list, struct policy_file *fp) { cond_node_t *cur; uint32_t len, items; uint32_t buf[1]; len = 0; for (cur = list; cur != NULL; cur = cur->next) len++; buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (cur = list; cur != NULL; cur = cur->next) { if (cond_write_node(p, cur, fp) != 0) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /* * Write a security context structure * to a policydb binary representation file. */ static int context_write(struct policydb *p, context_struct_t * c, struct policy_file *fp) { uint32_t buf[32]; size_t items, items2; items = 0; buf[items++] = cpu_to_le32(c->user); buf[items++] = cpu_to_le32(c->role); buf[items++] = cpu_to_le32(c->type); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; if ((p->policyvers >= POLICYDB_VERSION_MLS && p->policy_type == POLICY_KERN) || (p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policy_type == POLICY_BASE)) if (mls_write_range_helper(&c->range, fp)) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } /* * The following *_write functions are used to * write the symbol data to a policy database * binary representation file. */ static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { perm_datum_t *perdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; perdatum = (perm_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(perdatum->s.value); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { common_datum_t *comdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; comdatum = (common_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(comdatum->s.value); buf[items++] = cpu_to_le32(comdatum->permissions.nprim); buf[items++] = cpu_to_le32(comdatum->permissions.table->nel); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (hashtab_map(comdatum->permissions.table, perm_write, pd)) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int write_cons_helper(policydb_t * p, constraint_node_t * node, int allowxtarget, struct policy_file *fp) { constraint_node_t *c; constraint_expr_t *e; uint32_t buf[3], nexpr; int items; for (c = node; c; c = c->next) { nexpr = 0; for (e = c->expr; e; e = e->next) { nexpr++; } buf[0] = cpu_to_le32(c->permissions); buf[1] = cpu_to_le32(nexpr); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; for (e = c->expr; e; e = e->next) { items = 0; buf[0] = cpu_to_le32(e->expr_type); buf[1] = cpu_to_le32(e->attr); buf[2] = cpu_to_le32(e->op); items = put_entry(buf, sizeof(uint32_t), 3, fp); if (items != 3) return POLICYDB_ERROR; switch (e->expr_type) { case CEXPR_NAMES: if (!allowxtarget && (e->attr & CEXPR_XTARGET)) return POLICYDB_ERROR; if (ebitmap_write(&e->names, fp)) { return POLICYDB_ERROR; } if ((p->policy_type != POLICY_KERN && type_set_write(e->type_names, fp)) || (p->policy_type == POLICY_KERN && (p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES) && type_set_write(e->type_names, fp))) { return POLICYDB_ERROR; } break; default: break; } } } return POLICYDB_SUCCESS; } static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { class_datum_t *cladatum; constraint_node_t *c; uint32_t buf[32], ncons; size_t items, items2, len, len2; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; struct policydb *p = pd->p; cladatum = (class_datum_t *) datum; len = strlen(key); if (cladatum->comkey) len2 = strlen(cladatum->comkey); else len2 = 0; ncons = 0; for (c = cladatum->constraints; c; c = c->next) { ncons++; } items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(len2); buf[items++] = cpu_to_le32(cladatum->s.value); buf[items++] = cpu_to_le32(cladatum->permissions.nprim); if (cladatum->permissions.table) buf[items++] = cpu_to_le32(cladatum->permissions.table->nel); else buf[items++] = 0; buf[items++] = cpu_to_le32(ncons); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (cladatum->comkey) { items = put_entry(cladatum->comkey, 1, len2, fp); if (items != len2) return POLICYDB_ERROR; } if (hashtab_map(cladatum->permissions.table, perm_write, pd)) return POLICYDB_ERROR; if (write_cons_helper(p, cladatum->constraints, 0, fp)) return POLICYDB_ERROR; if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_VALIDATETRANS)) { /* write out the validatetrans rule */ ncons = 0; for (c = cladatum->validatetrans; c; c = c->next) { ncons++; } buf[0] = cpu_to_le32(ncons); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (write_cons_helper(p, cladatum->validatetrans, 1, fp)) return POLICYDB_ERROR; } if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) { buf[0] = cpu_to_le32(cladatum->default_user); buf[1] = cpu_to_le32(cladatum->default_role); buf[2] = cpu_to_le32(cladatum->default_range); items = put_entry(buf, sizeof(uint32_t), 3, fp); if (items != 3) return POLICYDB_ERROR; } if ((p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) || (p->policy_type == POLICY_BASE && p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) { buf[0] = cpu_to_le32(cladatum->default_type); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { role_datum_t *role; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; struct policydb *p = pd->p; role = (role_datum_t *) datum; /* * Role attributes are redundant for policy.X, skip them * when writing the roles symbol table. They are also skipped * when pp is downgraded. * * Their numbers would be deducted in policydb_write(). */ if ((role->flavor == ROLE_ATTRIB) && ((p->policy_type == POLICY_KERN) || (p->policy_type != POLICY_KERN && p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB))) return POLICYDB_SUCCESS; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(role->s.value); if (policydb_has_boundary_feature(p)) buf[items++] = cpu_to_le32(role->bounds); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (ebitmap_write(&role->dominates, fp)) return POLICYDB_ERROR; if (p->policy_type == POLICY_KERN) { if (ebitmap_write(&role->types.types, fp)) return POLICYDB_ERROR; } else { if (type_set_write(&role->types, fp)) return POLICYDB_ERROR; } if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) { buf[0] = cpu_to_le32(role->flavor); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (ebitmap_write(&role->roles, fp)) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { type_datum_t *typdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; struct policydb *p = pd->p; typdatum = (type_datum_t *) datum; /* * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY) * does not support to load entries of attribute, so we skip to write it. */ if (p->policy_type == POLICY_KERN && p->policyvers < POLICYDB_VERSION_BOUNDARY && typdatum->flavor == TYPE_ATTRIB) return POLICYDB_SUCCESS; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(typdatum->s.value); if (policydb_has_boundary_feature(p)) { uint32_t properties = 0; if (p->policy_type != POLICY_KERN && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY_ALIAS) { buf[items++] = cpu_to_le32(typdatum->primary); } if (typdatum->primary) properties |= TYPEDATUM_PROPERTY_PRIMARY; if (typdatum->flavor == TYPE_ATTRIB) { properties |= TYPEDATUM_PROPERTY_ATTRIBUTE; } else if (typdatum->flavor == TYPE_ALIAS && p->policy_type != POLICY_KERN) properties |= TYPEDATUM_PROPERTY_ALIAS; if (typdatum->flags & TYPE_FLAGS_PERMISSIVE && p->policy_type != POLICY_KERN) properties |= TYPEDATUM_PROPERTY_PERMISSIVE; buf[items++] = cpu_to_le32(properties); buf[items++] = cpu_to_le32(typdatum->bounds); } else { buf[items++] = cpu_to_le32(typdatum->primary); if (p->policy_type != POLICY_KERN) { buf[items++] = cpu_to_le32(typdatum->flavor); if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE) buf[items++] = cpu_to_le32(typdatum->flags); else if (typdatum->flags & TYPE_FLAGS_PERMISSIVE) WARN(fp->handle, "Warning! Module policy " "version %d cannot support permissive " "types, but one was defined", p->policyvers); } } items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; if (p->policy_type != POLICY_KERN) { if (ebitmap_write(&typdatum->types, fp)) return POLICYDB_ERROR; } items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; return POLICYDB_SUCCESS; } static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { user_datum_t *usrdatum; uint32_t buf[32]; size_t items, items2, len; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; struct policydb *p = pd->p; usrdatum = (user_datum_t *) datum; len = strlen(key); items = 0; buf[items++] = cpu_to_le32(len); buf[items++] = cpu_to_le32(usrdatum->s.value); if (policydb_has_boundary_feature(p)) buf[items++] = cpu_to_le32(usrdatum->bounds); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(key, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (p->policy_type == POLICY_KERN) { if (ebitmap_write(&usrdatum->roles.roles, fp)) return POLICYDB_ERROR; } else { if (role_set_write(&usrdatum->roles, fp)) return POLICYDB_ERROR; } if ((p->policyvers >= POLICYDB_VERSION_MLS && p->policy_type == POLICY_KERN) || (p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS && p->policy_type == POLICY_MOD) || (p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_MLS_USERS && p->policy_type == POLICY_BASE)) { if (mls_write_range_helper(&usrdatum->exp_range, fp)) return POLICYDB_ERROR; if (mls_write_level(&usrdatum->exp_dfltlevel, fp)) return POLICYDB_ERROR; } else if ((p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS && p->policy_type == POLICY_MOD) || (p->policyvers >= MOD_POLICYDB_VERSION_MLS_USERS && p->policy_type == POLICY_BASE)) { if (mls_write_semantic_range_helper(&usrdatum->range, fp)) return -1; if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp)) return -1; } return POLICYDB_SUCCESS; } static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) = { common_write, class_write, role_write, type_write, user_write, cond_write_bool, sens_write, cat_write,}; static int ocontext_write_xen(struct policydb_compat_info *info, policydb_t *p, struct policy_file *fp) { unsigned int i, j; size_t nel, items; uint32_t buf[32]; ocontext_t *c; for (i = 0; i < info->ocon_num; i++) { nel = 0; for (c = p->ocontexts[i]; c; c = c->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (c = p->ocontexts[i]; c; c = c->next) { switch (i) { case OCON_XEN_ISID: buf[0] = cpu_to_le32(c->sid[0]); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_XEN_PIRQ: buf[0] = cpu_to_le32(c->u.pirq); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_XEN_IOPORT: buf[0] = c->u.ioport.low_ioport; buf[1] = c->u.ioport.high_ioport; for (j = 0; j < 2; j++) buf[j] = cpu_to_le32(buf[j]); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_XEN_IOMEM: buf[0] = c->u.iomem.low_iomem; buf[1] = c->u.iomem.high_iomem; for (j = 0; j < 2; j++) buf[j] = cpu_to_le32(buf[j]); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_XEN_PCIDEVICE: buf[0] = cpu_to_le32(c->u.device); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; } } } return POLICYDB_SUCCESS; } static int ocontext_write_selinux(struct policydb_compat_info *info, policydb_t *p, struct policy_file *fp) { unsigned int i, j; size_t nel, items, len; uint32_t buf[32]; ocontext_t *c; for (i = 0; i < info->ocon_num; i++) { nel = 0; for (c = p->ocontexts[i]; c; c = c->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (c = p->ocontexts[i]; c; c = c->next) { switch (i) { case OCON_ISID: buf[0] = cpu_to_le32(c->sid[0]); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_FS: case OCON_NETIF: len = strlen(c->u.name); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(c->u.name, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; if (context_write(p, &c->context[1], fp)) return POLICYDB_ERROR; break; case OCON_PORT: buf[0] = c->u.port.protocol; buf[1] = c->u.port.low_port; buf[2] = c->u.port.high_port; for (j = 0; j < 3; j++) { buf[j] = cpu_to_le32(buf[j]); } items = put_entry(buf, sizeof(uint32_t), 3, fp); if (items != 3) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_NODE: buf[0] = c->u.node.addr; /* network order */ buf[1] = c->u.node.mask; /* network order */ items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_FSUSE: buf[0] = cpu_to_le32(c->v.behavior); len = strlen(c->u.name); buf[1] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; items = put_entry(c->u.name, 1, len, fp); if (items != len) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; case OCON_NODE6: for (j = 0; j < 4; j++) buf[j] = c->u.node6.addr[j]; /* network order */ for (j = 0; j < 4; j++) buf[j + 4] = c->u.node6.mask[j]; /* network order */ items = put_entry(buf, sizeof(uint32_t), 8, fp); if (items != 8) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; break; } } } return POLICYDB_SUCCESS; } static int ocontext_write(struct policydb_compat_info *info, policydb_t * p, struct policy_file *fp) { int rc = POLICYDB_ERROR; switch (p->target_platform) { case SEPOL_TARGET_SELINUX: rc = ocontext_write_selinux(info, p, fp); break; case SEPOL_TARGET_XEN: rc = ocontext_write_xen(info, p, fp); break; } return rc; } static int genfs_write(policydb_t * p, struct policy_file *fp) { genfs_t *genfs; ocontext_t *c; size_t nel = 0, items, len; uint32_t buf[32]; for (genfs = p->genfs; genfs; genfs = genfs->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (genfs = p->genfs; genfs; genfs = genfs->next) { len = strlen(genfs->fstype); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(genfs->fstype, 1, len, fp); if (items != len) return POLICYDB_ERROR; nel = 0; for (c = genfs->head; c; c = c->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (c = genfs->head; c; c = c->next) { len = strlen(c->u.name); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(c->u.name, 1, len, fp); if (items != len) return POLICYDB_ERROR; buf[0] = cpu_to_le32(c->v.sclass); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; if (context_write(p, &c->context[0], fp)) return POLICYDB_ERROR; } } return POLICYDB_SUCCESS; } static int range_write(policydb_t * p, struct policy_file *fp) { size_t nel, items; struct range_trans *rt; uint32_t buf[2]; int new_rangetr = (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_RANGETRANS); int warning_issued = 0; nel = 0; for (rt = p->range_tr; rt; rt = rt->next) { /* all range_transitions are written for the new format, only process related range_transitions are written for the old format, so count accordingly */ if (new_rangetr || rt->target_class == SECCLASS_PROCESS) nel++; } buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (rt = p->range_tr; rt; rt = rt->next) { if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) { if (!warning_issued) WARN(fp->handle, "Discarding range_transition " "rules for security classes other than " "\"process\""); warning_issued = 1; continue; } buf[0] = cpu_to_le32(rt->source_type); buf[1] = cpu_to_le32(rt->target_type); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; if (new_rangetr) { buf[0] = cpu_to_le32(rt->target_class); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } if (mls_write_range_helper(&rt->target_range, fp)) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } /************** module writing functions below **************/ static int avrule_write(avrule_t * avrule, struct policy_file *fp) { size_t items, items2; uint32_t buf[32], len; class_perm_node_t *cur; items = 0; buf[items++] = cpu_to_le32(avrule->specified); buf[items++] = cpu_to_le32(avrule->flags); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; if (type_set_write(&avrule->stypes, fp)) return POLICYDB_ERROR; if (type_set_write(&avrule->ttypes, fp)) return POLICYDB_ERROR; cur = avrule->perms; len = 0; while (cur) { len++; cur = cur->next; } items = 0; buf[items++] = cpu_to_le32(len); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; cur = avrule->perms; while (cur) { items = 0; buf[items++] = cpu_to_le32(cur->class); buf[items++] = cpu_to_le32(cur->data); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items2 != items) return POLICYDB_ERROR; cur = cur->next; } return POLICYDB_SUCCESS; } static int avrule_write_list(avrule_t * avrules, struct policy_file *fp) { uint32_t buf[32], len; avrule_t *avrule; avrule = avrules; len = 0; while (avrule) { len++; avrule = avrule->next; } buf[0] = cpu_to_le32(len); if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) return POLICYDB_ERROR; avrule = avrules; while (avrule) { avrule_write(avrule, fp); avrule = avrule->next; } return POLICYDB_SUCCESS; } static int only_process(ebitmap_t *in) { unsigned int i; ebitmap_node_t *node; ebitmap_for_each_bit(in, node, i) { if (ebitmap_node_get_bit(node, i) && i != SECCLASS_PROCESS - 1) return 0; } return 1; } static int role_trans_rule_write(policydb_t *p, role_trans_rule_t * t, struct policy_file *fp) { int nel = 0; size_t items; uint32_t buf[1]; role_trans_rule_t *tr; int warned = 0; int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS; for (tr = t; tr; tr = tr->next) if (new_role || only_process(&tr->classes)) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (tr = t; tr; tr = tr->next) { if (!new_role && !only_process(&tr->classes)) { if (!warned) WARN(fp->handle, "Discarding role_transition " "rules for security classes other than " "\"process\""); warned = 1; continue; } if (role_set_write(&tr->roles, fp)) return POLICYDB_ERROR; if (type_set_write(&tr->types, fp)) return POLICYDB_ERROR; if (new_role) if (ebitmap_write(&tr->classes, fp)) return POLICYDB_ERROR; buf[0] = cpu_to_le32(tr->new_role); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp) { int nel = 0; size_t items; uint32_t buf[1]; role_allow_rule_t *ra; for (ra = r; ra; ra = ra->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (ra = r; ra; ra = ra->next) { if (role_set_write(&ra->roles, fp)) return POLICYDB_ERROR; if (role_set_write(&ra->new_roles, fp)) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int filename_trans_rule_write(filename_trans_rule_t * t, struct policy_file *fp) { int nel = 0; size_t items; uint32_t buf[2], len; filename_trans_rule_t *ftr; for (ftr = t; ftr; ftr = ftr->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (ftr = t; ftr; ftr = ftr->next) { len = strlen(ftr->name); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(ftr->name, sizeof(char), len, fp); if (items != len) return POLICYDB_ERROR; if (type_set_write(&ftr->stypes, fp)) return POLICYDB_ERROR; if (type_set_write(&ftr->ttypes, fp)) return POLICYDB_ERROR; buf[0] = cpu_to_le32(ftr->tclass); buf[1] = cpu_to_le32(ftr->otype); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int range_trans_rule_write(range_trans_rule_t * t, struct policy_file *fp) { int nel = 0; size_t items; uint32_t buf[1]; range_trans_rule_t *rt; for (rt = t; rt; rt = rt->next) nel++; buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; for (rt = t; rt; rt = rt->next) { if (type_set_write(&rt->stypes, fp)) return POLICYDB_ERROR; if (type_set_write(&rt->ttypes, fp)) return POLICYDB_ERROR; if (ebitmap_write(&rt->tclasses, fp)) return POLICYDB_ERROR; if (mls_write_semantic_range_helper(&rt->trange, fp)) return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } static int scope_index_write(scope_index_t * scope_index, unsigned int num_scope_syms, struct policy_file *fp) { unsigned int i; uint32_t buf[1]; for (i = 0; i < num_scope_syms; i++) { if (ebitmap_write(scope_index->scope + i, fp) == -1) { return POLICYDB_ERROR; } } buf[0] = cpu_to_le32(scope_index->class_perms_len); if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { return POLICYDB_ERROR; } for (i = 0; i < scope_index->class_perms_len; i++) { if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) { return POLICYDB_ERROR; } } return POLICYDB_SUCCESS; } static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms, policydb_t * p, struct policy_file *fp) { struct policy_data pd; uint32_t buf[2]; int i; buf[0] = cpu_to_le32(decl->decl_id); buf[1] = cpu_to_le32(decl->enabled); if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) { return POLICYDB_ERROR; } if (cond_write_list(p, decl->cond_list, fp) == -1 || avrule_write_list(decl->avrules, fp) == -1 || role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 || role_allow_rule_write(decl->role_allow_rules, fp) == -1) { return POLICYDB_ERROR; } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && filename_trans_rule_write(decl->filename_trans_rules, fp)) return POLICYDB_ERROR; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && range_trans_rule_write(decl->range_tr_rules, fp) == -1) { return POLICYDB_ERROR; } if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 || scope_index_write(&decl->declared, num_scope_syms, fp) == -1) { return POLICYDB_ERROR; } pd.fp = fp; pd.p = p; for (i = 0; i < num_scope_syms; i++) { buf[0] = cpu_to_le32(decl->symtab[i].nprim); buf[1] = cpu_to_le32(decl->symtab[i].table->nel); if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) { return POLICYDB_ERROR; } if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) { return POLICYDB_ERROR; } } return POLICYDB_SUCCESS; } static int avrule_block_write(avrule_block_t * block, int num_scope_syms, policydb_t * p, struct policy_file *fp) { /* first write a count of the total number of blocks */ uint32_t buf[1], num_blocks = 0; avrule_block_t *cur; for (cur = block; cur != NULL; cur = cur->next) { num_blocks++; } buf[0] = cpu_to_le32(num_blocks); if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { return POLICYDB_ERROR; } /* now write each block */ for (cur = block; cur != NULL; cur = cur->next) { uint32_t num_decls = 0; avrule_decl_t *decl; /* write a count of number of branches */ for (decl = cur->branch_list; decl != NULL; decl = decl->next) { num_decls++; } buf[0] = cpu_to_le32(num_decls); if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { return POLICYDB_ERROR; } for (decl = cur->branch_list; decl != NULL; decl = decl->next) { if (avrule_decl_write(decl, num_scope_syms, p, fp) == -1) { return POLICYDB_ERROR; } } } return POLICYDB_SUCCESS; } static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) { scope_datum_t *scope = (scope_datum_t *) datum; struct policy_data *pd = ptr; struct policy_file *fp = pd->fp; uint32_t static_buf[32], *dyn_buf = NULL, *buf; size_t key_len = strlen(key); unsigned int items = 2 + scope->decl_ids_len, i; int rc; buf = static_buf; if (items >= (sizeof(static_buf) / 4)) { /* too many things required, so dynamically create a * buffer. this would have been easier with C99's * dynamic arrays... */ rc = POLICYDB_ERROR; dyn_buf = malloc(items * sizeof(*dyn_buf)); if (!dyn_buf) goto err; buf = dyn_buf; } buf[0] = cpu_to_le32(key_len); rc = POLICYDB_ERROR; if (put_entry(buf, sizeof(*buf), 1, fp) != 1 || put_entry(key, 1, key_len, fp) != key_len) goto err; buf[0] = cpu_to_le32(scope->scope); buf[1] = cpu_to_le32(scope->decl_ids_len); for (i = 0; i < scope->decl_ids_len; i++) buf[2 + i] = cpu_to_le32(scope->decl_ids[i]); rc = POLICYDB_ERROR; if (put_entry(buf, sizeof(*buf), items, fp) != items) goto err; rc = POLICYDB_SUCCESS; err: free(dyn_buf); return rc; } static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *args) { type_datum_t *typdatum = datum; uint32_t *p_nel = args; if (typdatum->flavor == TYPE_ATTRIB) { /* uncount attribute from total number of types */ (*p_nel)--; } return 0; } static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *args) { role_datum_t *role = datum; uint32_t *p_nel = args; if (role->flavor == ROLE_ATTRIB) { /* uncount attribute from total number of roles */ (*p_nel)--; } return 0; } /* * Write the configuration data in a policy database * structure to a policy database binary representation * file. */ int policydb_write(policydb_t * p, struct policy_file *fp) { unsigned int i, num_syms; uint32_t buf[32], config; size_t items, items2, len; struct policydb_compat_info *info; struct policy_data pd; char *policydb_str; if (p->unsupported_format) return POLICYDB_UNSUPPORTED; pd.fp = fp; pd.p = p; config = 0; if (p->mls) { if ((p->policyvers < POLICYDB_VERSION_MLS && p->policy_type == POLICY_KERN) || (p->policyvers < MOD_POLICYDB_VERSION_MLS && p->policy_type == POLICY_BASE) || (p->policyvers < MOD_POLICYDB_VERSION_MLS && p->policy_type == POLICY_MOD)) { ERR(fp->handle, "policy version %d cannot support MLS", p->policyvers); return POLICYDB_ERROR; } config |= POLICYDB_CONFIG_MLS; } config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown); /* Write the magic number and string identifiers. */ items = 0; if (p->policy_type == POLICY_KERN) { buf[items++] = cpu_to_le32(POLICYDB_MAGIC); len = strlen(policydb_target_strings[p->target_platform]); policydb_str = policydb_target_strings[p->target_platform]; } else { buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC); len = strlen(POLICYDB_MOD_STRING); policydb_str = POLICYDB_MOD_STRING; } buf[items++] = cpu_to_le32(len); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; items = put_entry(policydb_str, 1, len, fp); if (items != len) return POLICYDB_ERROR; /* Write the version, config, and table sizes. */ items = 0; info = policydb_lookup_compat(p->policyvers, p->policy_type, p->target_platform); if (!info) { ERR(fp->handle, "compatibility lookup failed for policy " "version %d", p->policyvers); return POLICYDB_ERROR; } if (p->policy_type != POLICY_KERN) { buf[items++] = cpu_to_le32(p->policy_type); } buf[items++] = cpu_to_le32(p->policyvers); buf[items++] = cpu_to_le32(config); buf[items++] = cpu_to_le32(info->sym_num); buf[items++] = cpu_to_le32(info->ocon_num); items2 = put_entry(buf, sizeof(uint32_t), items, fp); if (items != items2) return POLICYDB_ERROR; if (p->policy_type == POLICY_MOD) { /* Write module name and version */ len = strlen(p->name); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(p->name, 1, len, fp); if (items != len) return POLICYDB_ERROR; len = strlen(p->version); buf[0] = cpu_to_le32(len); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; items = put_entry(p->version, 1, len, fp); if (items != len) return POLICYDB_ERROR; } if ((p->policyvers >= POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_KERN) || (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_BASE) || (p->policyvers >= MOD_POLICYDB_VERSION_POLCAP && p->policy_type == POLICY_MOD)) { if (ebitmap_write(&p->policycaps, fp) == -1) return POLICYDB_ERROR; } if (p->policyvers < POLICYDB_VERSION_PERMISSIVE && p->policy_type == POLICY_KERN) { ebitmap_node_t *tnode; ebitmap_for_each_bit(&p->permissive_map, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { WARN(fp->handle, "Warning! Policy version %d cannot " "support permissive types, but some were defined", p->policyvers); break; } } } if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && p->policy_type == POLICY_KERN) { if (ebitmap_write(&p->permissive_map, fp) == -1) return POLICYDB_ERROR; } num_syms = info->sym_num; for (i = 0; i < num_syms; i++) { buf[0] = cpu_to_le32(p->symtab[i].nprim); buf[1] = p->symtab[i].table->nel; /* * A special case when writing type/attribute symbol table. * The kernel policy version less than 24 does not support * to load entries of attribute, so we have to re-calculate * the actual number of types except for attributes. */ if (i == SYM_TYPES && p->policyvers < POLICYDB_VERSION_BOUNDARY && p->policy_type == POLICY_KERN) { hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]); } /* * Another special case when writing role/attribute symbol * table, role attributes are redundant for policy.X, or * when the pp's version is not big enough. So deduct * their numbers from p_roles.table->nel. */ if ((i == SYM_ROLES) && ((p->policy_type == POLICY_KERN) || (p->policy_type != POLICY_KERN && p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB))) (void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]); buf[1] = cpu_to_le32(buf[1]); items = put_entry(buf, sizeof(uint32_t), 2, fp); if (items != 2) return POLICYDB_ERROR; if (hashtab_map(p->symtab[i].table, write_f[i], &pd)) return POLICYDB_ERROR; } if (p->policy_type == POLICY_KERN) { if (avtab_write(p, &p->te_avtab, fp)) return POLICYDB_ERROR; if (p->policyvers < POLICYDB_VERSION_BOOL) { if (p->p_bools.nprim) WARN(fp->handle, "Discarding " "booleans and conditional rules"); } else { if (cond_write_list(p, p->cond_list, fp)) return POLICYDB_ERROR; } if (role_trans_write(p, fp)) return POLICYDB_ERROR; if (role_allow_write(p->role_allow, fp)) return POLICYDB_ERROR; if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) { if (filename_trans_write(p->filename_trans, fp)) return POLICYDB_ERROR; } else { if (p->filename_trans) WARN(fp->handle, "Discarding filename type transition rules"); } } else { if (avrule_block_write(p->global, num_syms, p, fp) == -1) { return POLICYDB_ERROR; } for (i = 0; i < num_syms; i++) { buf[0] = cpu_to_le32(p->scope[i].table->nel); if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { return POLICYDB_ERROR; } if (hashtab_map(p->scope[i].table, scope_write, &pd)) return POLICYDB_ERROR; } } if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) { return POLICYDB_ERROR; } if ((p->policyvers >= POLICYDB_VERSION_MLS && p->policy_type == POLICY_KERN) || (p->policyvers >= MOD_POLICYDB_VERSION_MLS && p->policyvers < MOD_POLICYDB_VERSION_RANGETRANS && p->policy_type == POLICY_BASE)) { if (range_write(p, fp)) { return POLICYDB_ERROR; } } if (p->policy_type == POLICY_KERN && p->policyvers >= POLICYDB_VERSION_AVTAB) { for (i = 0; i < p->p_types.nprim; i++) { if (ebitmap_write(&p->type_attr_map[i], fp) == -1) return POLICYDB_ERROR; } } return POLICYDB_SUCCESS; } libsepol-2.2/tests/000077500000000000000000000000001223423440700143315ustar00rootroot00000000000000libsepol-2.2/tests/Makefile000066400000000000000000000034161223423440700157750ustar00rootroot00000000000000M4 ?= m4 MKDIR ?= mkdir EXE ?= libsepol-tests CFLAGS += -g3 -gdwarf-2 -o0 -Wall -W -Wundef -Wmissing-noreturn -Wmissing-format-attribute -Wno-unused-parameter -Werror # Statically link libsepol on the assumption that we are going to # be testing internal functions. LIBSEPOL := ../src/libsepol.a # In order to load source policies we need to link in the checkpolicy/checkmodule parser and util code. # This is less than ideal, but it makes the tests easier to maintain by allowing source policies # to be loaded directly. CHECKPOLICY := ../../checkpolicy/ CPPFLAGS += -I../include/ -I$(CHECKPOLICY) # test program object files objs := $(patsubst %.c,%.o,$(wildcard *.c)) parserobjs := $(CHECKPOLICY)queue.o $(CHECKPOLICY)y.tab.o \ $(CHECKPOLICY)parse_util.o $(CHECKPOLICY)lex.yy.o \ $(CHECKPOLICY)policy_define.o $(CHECKPOLICY)module_compiler.o # test policy pieces m4support := $(wildcard policies/support/*.spt) testsuites := $(wildcard policies/test-*) policysrc := $(foreach path,$(testsuites),$(wildcard $(path)/*.conf)) stdpol := $(addsuffix .std,$(policysrc)) mlspol := $(addsuffix .mls,$(policysrc)) policies := $(stdpol) $(mlspol) all: $(EXE) $(policies) policies: $(policies) $(EXE): $(objs) $(parserobjs) $(LIBSEPOL) $(CC) $(CFLAGS) $(CPPFLAGS) $(objs) $(parserobjs) -lfl -lcunit -lcurses $(LIBSEPOL) -o $@ %.conf.std: $(m4support) %.conf $(M4) $(M4PARAMS) $^ > $@ %.conf.mls: $(m4support) %.conf $(M4) $(M4PARAMS) -D enable_mls $^ > $@ clean: rm -f $(objs) $(EXE) rm -f $(policies) rm -f policies/test-downgrade/policy.hi policies/test-downgrade/policy.lo test: $(EXE) $(policies) $(MKDIR) -p policies/test-downgrade ../../checkpolicy/checkpolicy -M policies/test-cond/refpolicy-base.conf -o policies/test-downgrade/policy.hi ./$(EXE) .PHONY: all policies clean test libsepol-2.2/tests/debug.c000066400000000000000000000034431223423440700155670ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ /* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */ #include "debug.h" #include void print_ebitmap(ebitmap_t * bitmap, FILE * fp) { uint32_t i; for (i = 0; i < bitmap->highbit; i++) { fprintf(fp, "%d", ebitmap_get_bit(bitmap, i)); } fprintf(fp, "\n"); } /* stolen from dispol.c */ 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! (%d)", cur->expr_type); break; } } } libsepol-2.2/tests/debug.h000066400000000000000000000022111223423440700155640ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ /* This includes functions used to debug tests (display bitmaps, conditional expressions, etc */ #include #include extern void print_ebitmap(ebitmap_t * bitmap, FILE * fp); extern void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp); libsepol-2.2/tests/helpers.c000066400000000000000000000042151223423440700161410ustar00rootroot00000000000000/* * Author: Joshua Brindle * Chad Sellers * * 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 */ /* This has helper functions that are common between tests */ #include "helpers.h" #include "parse_util.h" #include #include #include #include #include int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name) { char filename[PATH_MAX]; if (mls) { if (snprintf(filename, PATH_MAX, "policies/%s/%s.mls", test_name, policy_name) < 0) { return -1; } } else { if (snprintf(filename, PATH_MAX, "policies/%s/%s.std", test_name, policy_name) < 0) { return -1; } } if (policydb_init(p)) { fprintf(stderr, "Out of memory"); return -1; } p->policy_type = policy_type; p->mls = mls; if (read_source_policy(p, filename, test_name)) { fprintf(stderr, "failed to read policy %s\n", filename); policydb_destroy(p); return -1; } return 0; } avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym) { scope_datum_t *scope = (scope_datum_t *) hashtab_search(p->scope[symtab].table, sym); if (scope == NULL) { return NULL; } if (scope->scope != SCOPE_DECL) { return NULL; } if (scope->decl_ids_len != 1) { return NULL; } return p->decl_val_to_struct[scope->decl_ids[0] - 1]; } libsepol-2.2/tests/helpers.h000066400000000000000000000043601223423440700161470ustar00rootroot00000000000000/* * Author: Joshua Brindle * Chad Sellers * * 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 */ #ifndef __COMMON_H__ #define __COMMON_H__ #include #include /* helper functions */ /* Load a source policy into p. policydb_init will called within this function. * * Example: test_load_policy(p, POLICY_BASE, 1, "foo", "base.conf") will load the * policy "policies/foo/mls/base.conf" into p. * * Arguments: * p policydb_t into which the policy will be read. This should be * malloc'd but not passed to policydb_init. * policy_type Type of policy expected - POLICY_BASE or POLICY_MOD. * mls Boolean value indicating whether an mls policy is expected. * test_name Name of the test which will be the name of the directory in * which the policies are stored. * policy_name Name of the policy in the directory. * * Returns: * 0 success * -1 error - the policydb will be destroyed but not freed. */ extern int test_load_policy(policydb_t * p, int policy_type, int mls, const char *test_name, const char *policy_name); /* Find an avrule_decl_t by a unique symbol. If the symbol is declared in more * than one decl an error is returned. * * Returns: * decl success * NULL error (including more than one declaration) */ extern avrule_decl_t *test_find_decl_by_sym(policydb_t * p, int symtab, char *sym); #endif libsepol-2.2/tests/libsepol-tests.c000066400000000000000000000052341223423440700174520ustar00rootroot00000000000000/* * 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 "test-cond.h" #include "test-linker.h" #include "test-expander.h" #include "test-deps.h" #include "test-downgrade.h" #include #include #include #include #include #include int mls; #define DECLARE_SUITE(name) \ suite = CU_add_suite(#name, name##_test_init, name##_test_cleanup); \ if (NULL == suite) { \ CU_cleanup_registry(); \ return CU_get_error(); } \ if (name##_add_tests(suite)) { \ CU_cleanup_registry(); \ return CU_get_error(); } static void usage(char *progname) { printf("usage: %s [options]\n", progname); printf("options:\n"); printf("\t-v, --verbose\t\t\tverbose output\n"); printf("\t-i, --interactive\t\tinteractive console\n"); } static int do_tests(int interactive, int verbose) { CU_pSuite suite = NULL; if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); DECLARE_SUITE(cond); DECLARE_SUITE(linker); DECLARE_SUITE(expander); DECLARE_SUITE(deps); DECLARE_SUITE(downgrade); if (verbose) CU_basic_set_mode(CU_BRM_VERBOSE); else CU_basic_set_mode(CU_BRM_NORMAL); if (interactive) CU_console_run_tests(); else CU_basic_run_tests(); CU_cleanup_registry(); return CU_get_error(); } int main(int argc, char **argv) { int i, verbose = 1, interactive = 0; struct option opts[] = { {"verbose", 0, NULL, 'v'}, {"interactive", 0, NULL, 'i'}, {NULL, 0, NULL, 0} }; while ((i = getopt_long(argc, argv, "vi", opts, NULL)) != -1) { switch (i) { case 'v': verbose = 1; break; case 'i': interactive = 1; break; case 'h': default:{ usage(argv[0]); exit(1); } } } /* first do the non-mls tests */ mls = 0; if (do_tests(interactive, verbose)) return -1; /* then with mls */ mls = 1; if (do_tests(interactive, verbose)) return -1; return 0; } libsepol-2.2/tests/policies/000077500000000000000000000000001223423440700161405ustar00rootroot00000000000000libsepol-2.2/tests/policies/support/000077500000000000000000000000001223423440700176545ustar00rootroot00000000000000libsepol-2.2/tests/policies/support/misc_macros.spt000066400000000000000000000011751223423440700227070ustar00rootroot00000000000000 ######################################## # # Helper macros # ######################################## # # gen_user(username, prefix, role_set, mls_defaultlevel, mls_range, [mcs_categories]) # define(`gen_user',`dnl ifdef(`users_extra',`dnl ifelse(`$2',,,`user $1 prefix $2;') ',`dnl user $1 roles { $3 }`'ifdef(`enable_mls', ` level $4 range $5')`'ifdef(`enable_mcs',` level s0 range s0`'ifelse(`$6',,,` - s0:$6')'); ')dnl ') ######################################## # # gen_context(context,mls_sensitivity,[mcs_categories]) # define(`gen_context',`$1`'ifdef(`enable_mls',`:$2')`'ifdef(`enable_mcs',`:s0`'ifelse(`$3',,,`:$3')')') dnl libsepol-2.2/tests/policies/test-cond/000077500000000000000000000000001223423440700200405ustar00rootroot00000000000000libsepol-2.2/tests/policies/test-cond/refpolicy-base.conf000066400000000000000000002061161223423440700236210ustar00rootroot00000000000000class security class process class system class capability class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket class sem class msg class msgq class shm class ipc class passwd # userspace class drawable # userspace class window # userspace class gc # userspace class font # userspace class colormap # userspace class property # userspace class cursor # userspace class xclient # userspace class xinput # userspace class xserver # userspace class xextension # userspace class pax class netlink_route_socket class netlink_firewall_socket class netlink_tcpdiag_socket class netlink_nflog_socket class netlink_xfrm_socket class netlink_selinux_socket class netlink_audit_socket class netlink_ip6fw_socket class netlink_dnrt_socket class dbus # userspace class nscd # userspace class association class netlink_kobject_uevent_socket sid kernel sid security sid unlabeled sid fs sid file sid file_labels sid init sid any_socket sid port sid netif sid netmsg sid node sid igmp_packet sid icmp_socket sid tcp_socket sid sysctl_modprobe sid sysctl sid sysctl_fs sid sysctl_kernel sid sysctl_net sid sysctl_net_unix sid sysctl_vm sid sysctl_dev sid kmod sid policy sid scmp_packet sid devnull common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } common socket { ioctl read write create getattr setattr lock relabelfrom relabelto append bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } common ipc { create destroy getattr setattr read write associate unix_read unix_write } class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint execmod } class lnk_file inherits file class chr_file inherits file { execute_no_trans entrypoint execmod } class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom node_bind name_connect } class udp_socket inherits socket { node_bind } class rawip_socket inherits socket { node_bind } class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share getattr setexec setfscreate noatsecure siginh setrlimit rlimitinh dyntransition setcurrent execmem execstack execheap } class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } class security { compute_av compute_create compute_member check_context load_policy compute_relabel compute_user setenforce # was avc_toggle in system class setbool setsecparam setcheckreqprot } class system { ipc_info syslog_read syslog_mod syslog_console } class capability { chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control } class passwd { passwd # change another user passwd chfn # change another user finger info chsh # change another user shell rootok # pam_rootok check (skip auth) crontab # crontab on another user } class drawable { create destroy draw copy getattr } class gc { create free getattr setattr } class window { addchild create destroy map unmap chstack chproplist chprop listprop getattr setattr setfocus move chselection chparent ctrllife enumerate transparent mousemotion clientcomevent inputevent drawevent windowchangeevent windowchangerequest serverchangeevent extensionevent } class font { load free getattr use } class colormap { create free install uninstall list read store getattr setattr } class property { create free read write } class cursor { create createglyph free assign setattr } class xclient { kill } class xinput { lookup getattr setattr setfocus warppointer activegrab passivegrab ungrab bell mousemotion relabelinput } class xserver { screensaver gethostlist sethostlist getfontpath setfontpath getattr grab ungrab } class xextension { query use } class pax { pageexec # Paging based non-executable pages emutramp # Emulate trampolines mprotect # Restrict mprotect() randmmap # Randomize mmap() base randexec # Randomize ET_EXEC base segmexec # Segmentation based non-executable pages } class netlink_route_socket inherits socket { nlmsg_read nlmsg_write } class netlink_firewall_socket inherits socket { nlmsg_read nlmsg_write } class netlink_tcpdiag_socket inherits socket { nlmsg_read nlmsg_write } class netlink_nflog_socket inherits socket class netlink_xfrm_socket inherits socket { nlmsg_read nlmsg_write } class netlink_selinux_socket inherits socket class netlink_audit_socket inherits socket { nlmsg_read nlmsg_write nlmsg_relay nlmsg_readpriv } class netlink_ip6fw_socket inherits socket { nlmsg_read nlmsg_write } class netlink_dnrt_socket inherits socket class dbus { acquire_svc send_msg } class nscd { getpwd getgrp gethost getstat admin shmempwd shmemgrp shmemhost } class association { sendto recvfrom setcontext } class netlink_kobject_uevent_socket inherits socket sensitivity s0; dominance { s0 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; category c24; category c25; category c26; category c27; category c28; category c29; category c30; category c31; category c32; category c33; category c34; category c35; category c36; category c37; category c38; category c39; category c40; category c41; category c42; category c43; category c44; category c45; category c46; category c47; category c48; category c49; category c50; category c51; category c52; category c53; category c54; category c55; category c56; category c57; category c58; category c59; category c60; category c61; category c62; category c63; category c64; category c65; category c66; category c67; category c68; category c69; category c70; category c71; category c72; category c73; category c74; category c75; category c76; category c77; category c78; category c79; category c80; category c81; category c82; category c83; category c84; category c85; category c86; category c87; category c88; category c89; category c90; category c91; category c92; category c93; category c94; category c95; category c96; category c97; category c98; category c99; category c100; category c101; category c102; category c103; category c104; category c105; category c106; category c107; category c108; category c109; category c110; category c111; category c112; category c113; category c114; category c115; category c116; category c117; category c118; category c119; category c120; category c121; category c122; category c123; category c124; category c125; category c126; category c127; category c128; category c129; category c130; category c131; category c132; category c133; category c134; category c135; category c136; category c137; category c138; category c139; category c140; category c141; category c142; category c143; category c144; category c145; category c146; category c147; category c148; category c149; category c150; category c151; category c152; category c153; category c154; category c155; category c156; category c157; category c158; category c159; category c160; category c161; category c162; category c163; category c164; category c165; category c166; category c167; category c168; category c169; category c170; category c171; category c172; category c173; category c174; category c175; category c176; category c177; category c178; category c179; category c180; category c181; category c182; category c183; category c184; category c185; category c186; category c187; category c188; category c189; category c190; category c191; category c192; category c193; category c194; category c195; category c196; category c197; category c198; category c199; category c200; category c201; category c202; category c203; category c204; category c205; category c206; category c207; category c208; category c209; category c210; category c211; category c212; category c213; category c214; category c215; category c216; category c217; category c218; category c219; category c220; category c221; category c222; category c223; category c224; category c225; category c226; category c227; category c228; category c229; category c230; category c231; category c232; category c233; category c234; category c235; category c236; category c237; category c238; category c239; category c240; category c241; category c242; category c243; category c244; category c245; category c246; category c247; category c248; category c249; category c250; category c251; category c252; category c253; category c254; category c255; level s0:c0.c255; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } (h1 dom h2); mlsconstrain file { create relabelto } ((h1 dom h2) and (l2 eq h2)); mlsconstrain file { read } ((h1 dom h2) or ( t2 == domain ) or ( t1 == mlsfileread )); mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { relabelfrom } ( h1 dom h2 ); mlsconstrain { dir lnk_file chr_file blk_file sock_file fifo_file } { create relabelto } (( h1 dom h2 ) and ( l2 eq h2 )); mlsconstrain process { ptrace } ( h1 dom h2 ); mlsconstrain process { sigkill sigstop } ( h1 dom h2 ) or ( t1 == mcskillall ); mlsconstrain xextension query ( t1 == mlsfileread ); attribute netif_type; attribute node_type; attribute port_type; attribute reserved_port_type; attribute device_node; attribute memory_raw_read; attribute memory_raw_write; attribute domain; attribute unconfined_domain_type; attribute set_curr_context; attribute entry_type; attribute privfd; attribute can_change_process_identity; attribute can_change_process_role; attribute can_change_object_identity; attribute can_system_change; attribute process_user_target; attribute cron_source_domain; attribute cron_job_domain; attribute process_uncond_exempt; # add userhelperdomain to this one attribute file_type; attribute lockfile; attribute mountpoint; attribute pidfile; attribute polydir; attribute usercanread; attribute polyparent; attribute polymember; attribute security_file_type; attribute tmpfile; attribute tmpfsfile; attribute filesystem_type; attribute noxattrfs; attribute can_load_kernmodule; attribute can_receive_kernel_messages; attribute kern_unconfined; attribute proc_type; attribute sysctl_type; attribute mcskillall; attribute mlsfileread; attribute mlsfilereadtoclr; attribute mlsfilewrite; attribute mlsfilewritetoclr; attribute mlsfileupgrade; attribute mlsfiledowngrade; attribute mlsnetread; attribute mlsnetreadtoclr; attribute mlsnetwrite; attribute mlsnetwritetoclr; attribute mlsnetupgrade; attribute mlsnetdowngrade; attribute mlsnetrecvall; attribute mlsipcread; attribute mlsipcreadtoclr; attribute mlsipcwrite; attribute mlsipcwritetoclr; attribute mlsprocread; attribute mlsprocreadtoclr; attribute mlsprocwrite; attribute mlsprocwritetoclr; attribute mlsprocsetsl; attribute mlsxwinread; attribute mlsxwinreadtoclr; attribute mlsxwinwrite; attribute mlsxwinwritetoclr; attribute mlsxwinreadproperty; attribute mlsxwinwriteproperty; attribute mlsxwinreadcolormap; attribute mlsxwinwritecolormap; attribute mlsxwinwritexinput; attribute mlstrustedobject; attribute privrangetrans; attribute mlsrangetrans; attribute can_load_policy; attribute can_setenforce; attribute can_setsecparam; attribute ttynode; attribute ptynode; attribute server_ptynode; attribute serial_device; type bin_t; type sbin_t; type ls_exec_t; type shell_exec_t; type chroot_exec_t; type ppp_device_t; type tun_tap_device_t; type port_t, port_type; type reserved_port_t, port_type, reserved_port_type; type afs_bos_port_t, port_type; type afs_fs_port_t, port_type; type afs_ka_port_t, port_type; type afs_pt_port_t, port_type; type afs_vl_port_t, port_type; type amanda_port_t, port_type; type amavisd_recv_port_t, port_type; type amavisd_send_port_t, port_type; type asterisk_port_t, port_type; type auth_port_t, port_type; type bgp_port_t, port_type; type biff_port_t, port_type, reserved_port_type; type clamd_port_t, port_type; type clockspeed_port_t, port_type; type comsat_port_t, port_type; type cvs_port_t, port_type; type dcc_port_t, port_type; type dbskkd_port_t, port_type; type dhcpc_port_t, port_type; type dhcpd_port_t, port_type; type dict_port_t, port_type; type distccd_port_t, port_type; type dns_port_t, port_type; type fingerd_port_t, port_type; type ftp_data_port_t, port_type; type ftp_port_t, port_type; type gatekeeper_port_t, port_type; type giftd_port_t, port_type; type gopher_port_t, port_type; type http_cache_port_t, port_type; type http_port_t, port_type; type howl_port_t, port_type; type hplip_port_t, port_type; type i18n_input_port_t, port_type; type imaze_port_t, port_type; type inetd_child_port_t, port_type; type innd_port_t, port_type; type ipp_port_t, port_type; type ircd_port_t, port_type; type isakmp_port_t, port_type; type jabber_client_port_t, port_type; type jabber_interserver_port_t, port_type; type kerberos_admin_port_t, port_type; type kerberos_master_port_t, port_type; type kerberos_port_t, port_type; type ktalkd_port_t, port_type; type ldap_port_t, port_type; type lrrd_port_t, port_type; type mail_port_t, port_type; type monopd_port_t, port_type; type mysqld_port_t, port_type; type nessus_port_t, port_type; type nmbd_port_t, port_type; type ntp_port_t, port_type; type openvpn_port_t, port_type; type pegasus_http_port_t, port_type; type pegasus_https_port_t, port_type; type pop_port_t, port_type; type portmap_port_t, port_type; type postgresql_port_t, port_type; type postgrey_port_t, port_type; type printer_port_t, port_type; type ptal_port_t, port_type; type pxe_port_t, port_type; type pyzor_port_t, port_type; type radacct_port_t, port_type; type radius_port_t, port_type; type razor_port_t, port_type; type rlogind_port_t, port_type; type rndc_port_t, port_type; type router_port_t, port_type; type rsh_port_t, port_type; type rsync_port_t, port_type; type smbd_port_t, port_type; type smtp_port_t, port_type; type snmp_port_t, port_type; type spamd_port_t, port_type; type ssh_port_t, port_type; type soundd_port_t, port_type; type socks_port_t, port_type; type stunnel_port_t, port_type; type swat_port_t, port_type; type syslogd_port_t, port_type; type telnetd_port_t, port_type; type tftp_port_t, port_type; type transproxy_port_t, port_type; type utcpserver_port_t, port_type; type uucpd_port_t, port_type; type vnc_port_t, port_type; type xserver_port_t, port_type; type xen_port_t, port_type; type zebra_port_t, port_type; type zope_port_t, port_type; type node_t, node_type; type compat_ipv4_node_t alias node_compat_ipv4_t, node_type; type inaddr_any_node_t alias node_inaddr_any_t, node_type; type node_internal_t, node_type; type link_local_node_t alias node_link_local_t, node_type; type lo_node_t alias node_lo_t, node_type; type mapped_ipv4_node_t alias node_mapped_ipv4_t, node_type; type multicast_node_t alias node_multicast_t, node_type; type site_local_node_t alias node_site_local_t, node_type; type unspec_node_t alias node_unspec_t, node_type; type netif_t, netif_type; type device_t; type agp_device_t; type apm_bios_t; type cardmgr_dev_t; type clock_device_t; type cpu_device_t; type crypt_device_t; type dri_device_t; type event_device_t; type framebuf_device_t; type lvm_control_t; type memory_device_t; type misc_device_t; type mouse_device_t; type mtrr_device_t; type null_device_t; type power_device_t; type printer_device_t; type random_device_t; type scanner_device_t; type sound_device_t; type sysfs_t; type urandom_device_t; type usbfs_t alias usbdevfs_t; type usb_device_t; type v4l_device_t; type xserver_misc_device_t; type zero_device_t; type xconsole_device_t; type devfs_control_t; type boot_t; type default_t, file_type, mountpoint; type etc_t, file_type; type etc_runtime_t, file_type; type file_t, file_type, mountpoint; type home_root_t, file_type, mountpoint; type lost_found_t, file_type; type mnt_t, file_type, mountpoint; type modules_object_t; type no_access_t, file_type; type poly_t, file_type; type readable_t, file_type; type root_t, file_type, mountpoint; type src_t, file_type, mountpoint; type system_map_t; type tmp_t, mountpoint; #, polydir type usr_t, file_type, mountpoint; type var_t, file_type, mountpoint; type var_lib_t, file_type, mountpoint; type var_lock_t, file_type, lockfile; type var_run_t, file_type, pidfile; type var_spool_t; type fs_t; type bdev_t; type binfmt_misc_fs_t; type capifs_t; type configfs_t; type eventpollfs_t; type futexfs_t; type hugetlbfs_t; type inotifyfs_t; type nfsd_fs_t; type ramfs_t; type romfs_t; type rpc_pipefs_t; type tmpfs_t; type autofs_t, noxattrfs; type cifs_t alias sambafs_t, noxattrfs; type dosfs_t, noxattrfs; type iso9660_t, filesystem_type, noxattrfs; type removable_t, noxattrfs; type nfs_t, filesystem_type, noxattrfs; type kernel_t, can_load_kernmodule; type debugfs_t; type proc_t, proc_type; type proc_kmsg_t, proc_type; type proc_kcore_t, proc_type; type proc_mdstat_t, proc_type; type proc_net_t, proc_type; type proc_xen_t, proc_type; type sysctl_t, sysctl_type; type sysctl_irq_t, sysctl_type; type sysctl_rpc_t, sysctl_type; type sysctl_fs_t, sysctl_type; type sysctl_kernel_t, sysctl_type; type sysctl_modprobe_t, sysctl_type; type sysctl_hotplug_t, sysctl_type; type sysctl_net_t, sysctl_type; type sysctl_net_unix_t, sysctl_type; type sysctl_vm_t, sysctl_type; type sysctl_dev_t, sysctl_type; type unlabeled_t; type auditd_exec_t; type crond_exec_t; type cupsd_exec_t; type getty_t; type init_t; type init_exec_t; type initrc_t; type initrc_exec_t; type login_exec_t; type sshd_exec_t; type su_exec_t; type udev_exec_t; type unconfined_t; type xdm_exec_t; type lvm_exec_t; type security_t; type bsdpty_device_t; type console_device_t; type devpts_t; type devtty_t; type ptmx_t; type tty_device_t, serial_device; type usbtty_device_t, serial_device; bool secure_mode false; bool secure_mode_insmod false; bool secure_mode_policyload false; bool allow_cvs_read_shadow false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool allow_ftpd_anon_write false; bool allow_gssd_read_tmp true; bool allow_httpd_anon_write false; bool allow_java_execstack false; bool allow_kerberos true; bool allow_rsync_anon_write false; bool allow_saslauthd_read_shadow false; bool allow_smbd_anon_write false; bool allow_ptrace false; bool allow_ypbind false; bool fcron_crond false; bool ftp_home_dir false; bool ftpd_is_daemon true; bool httpd_builtin_scripting true; bool httpd_can_network_connect false; bool httpd_can_network_connect_db false; bool httpd_can_network_relay false; bool httpd_enable_cgi true; bool httpd_enable_ftp_server false; bool httpd_enable_homedirs true; bool httpd_ssi_exec true; bool httpd_tty_comm false; bool httpd_unified true; bool named_write_master_zones false; bool nfs_export_all_rw true; bool nfs_export_all_ro true; bool pppd_can_insmod false; bool read_default_t true; bool run_ssh_inetd false; bool samba_enable_home_dirs false; bool spamassasin_can_network false; bool squid_connect_any false; bool ssh_sysadm_login false; bool stunnel_is_daemon false; bool use_nfs_home_dirs false; bool use_samba_home_dirs false; bool user_ping true; bool spamd_enable_home_dirs true; allow bin_t fs_t:filesystem associate; allow bin_t noxattrfs:filesystem associate; typeattribute bin_t file_type; allow sbin_t fs_t:filesystem associate; allow sbin_t noxattrfs:filesystem associate; typeattribute sbin_t file_type; allow ls_exec_t fs_t:filesystem associate; allow ls_exec_t noxattrfs:filesystem associate; typeattribute ls_exec_t file_type; typeattribute ls_exec_t entry_type; allow shell_exec_t fs_t:filesystem associate; allow shell_exec_t noxattrfs:filesystem associate; typeattribute shell_exec_t file_type; allow chroot_exec_t fs_t:filesystem associate; allow chroot_exec_t noxattrfs:filesystem associate; typeattribute chroot_exec_t file_type; typeattribute ppp_device_t device_node; allow ppp_device_t fs_t:filesystem associate; allow ppp_device_t tmpfs_t:filesystem associate; allow ppp_device_t tmp_t:filesystem associate; typeattribute tun_tap_device_t device_node; allow tun_tap_device_t fs_t:filesystem associate; allow tun_tap_device_t tmpfs_t:filesystem associate; allow tun_tap_device_t tmp_t:filesystem associate; typeattribute auth_port_t reserved_port_type; typeattribute bgp_port_t reserved_port_type; typeattribute bgp_port_t reserved_port_type; typeattribute comsat_port_t reserved_port_type; typeattribute dhcpc_port_t reserved_port_type; typeattribute dhcpd_port_t reserved_port_type; typeattribute dhcpd_port_t reserved_port_type; typeattribute dhcpd_port_t reserved_port_type; typeattribute dhcpd_port_t reserved_port_type; typeattribute dhcpd_port_t reserved_port_type; typeattribute dns_port_t reserved_port_type; typeattribute dns_port_t reserved_port_type; typeattribute fingerd_port_t reserved_port_type; typeattribute ftp_data_port_t reserved_port_type; typeattribute ftp_port_t reserved_port_type; typeattribute gopher_port_t reserved_port_type; typeattribute gopher_port_t reserved_port_type; typeattribute http_port_t reserved_port_type; typeattribute http_port_t reserved_port_type; typeattribute http_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute inetd_child_port_t reserved_port_type; typeattribute innd_port_t reserved_port_type; typeattribute ipp_port_t reserved_port_type; typeattribute ipp_port_t reserved_port_type; typeattribute isakmp_port_t reserved_port_type; typeattribute kerberos_admin_port_t reserved_port_type; typeattribute kerberos_admin_port_t reserved_port_type; typeattribute kerberos_admin_port_t reserved_port_type; typeattribute kerberos_port_t reserved_port_type; typeattribute kerberos_port_t reserved_port_type; typeattribute kerberos_port_t reserved_port_type; typeattribute kerberos_port_t reserved_port_type; typeattribute ktalkd_port_t reserved_port_type; typeattribute ktalkd_port_t reserved_port_type; typeattribute ldap_port_t reserved_port_type; typeattribute ldap_port_t reserved_port_type; typeattribute ldap_port_t reserved_port_type; typeattribute ldap_port_t reserved_port_type; typeattribute nmbd_port_t reserved_port_type; typeattribute nmbd_port_t reserved_port_type; typeattribute nmbd_port_t reserved_port_type; typeattribute ntp_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute pop_port_t reserved_port_type; typeattribute portmap_port_t reserved_port_type; typeattribute portmap_port_t reserved_port_type; typeattribute printer_port_t reserved_port_type; typeattribute rlogind_port_t reserved_port_type; typeattribute rndc_port_t reserved_port_type; typeattribute router_port_t reserved_port_type; typeattribute rsh_port_t reserved_port_type; typeattribute rsync_port_t reserved_port_type; typeattribute rsync_port_t reserved_port_type; typeattribute smbd_port_t reserved_port_type; typeattribute smbd_port_t reserved_port_type; typeattribute smtp_port_t reserved_port_type; typeattribute smtp_port_t reserved_port_type; typeattribute smtp_port_t reserved_port_type; typeattribute snmp_port_t reserved_port_type; typeattribute snmp_port_t reserved_port_type; typeattribute snmp_port_t reserved_port_type; typeattribute spamd_port_t reserved_port_type; typeattribute ssh_port_t reserved_port_type; typeattribute swat_port_t reserved_port_type; typeattribute syslogd_port_t reserved_port_type; typeattribute telnetd_port_t reserved_port_type; typeattribute tftp_port_t reserved_port_type; typeattribute uucpd_port_t reserved_port_type; allow device_t tmpfs_t:filesystem associate; allow device_t fs_t:filesystem associate; allow device_t noxattrfs:filesystem associate; typeattribute device_t file_type; allow device_t fs_t:filesystem associate; allow device_t noxattrfs:filesystem associate; typeattribute device_t file_type; typeattribute device_t mountpoint; allow device_t tmp_t:filesystem associate; typeattribute agp_device_t device_node; allow agp_device_t fs_t:filesystem associate; allow agp_device_t tmpfs_t:filesystem associate; allow agp_device_t tmp_t:filesystem associate; typeattribute apm_bios_t device_node; allow apm_bios_t fs_t:filesystem associate; allow apm_bios_t tmpfs_t:filesystem associate; allow apm_bios_t tmp_t:filesystem associate; typeattribute cardmgr_dev_t device_node; allow cardmgr_dev_t fs_t:filesystem associate; allow cardmgr_dev_t tmpfs_t:filesystem associate; allow cardmgr_dev_t tmp_t:filesystem associate; allow cardmgr_dev_t fs_t:filesystem associate; allow cardmgr_dev_t noxattrfs:filesystem associate; typeattribute cardmgr_dev_t file_type; allow cardmgr_dev_t fs_t:filesystem associate; allow cardmgr_dev_t noxattrfs:filesystem associate; typeattribute cardmgr_dev_t file_type; typeattribute cardmgr_dev_t polymember; allow cardmgr_dev_t tmpfs_t:filesystem associate; typeattribute cardmgr_dev_t tmpfile; allow cardmgr_dev_t tmp_t:filesystem associate; typeattribute clock_device_t device_node; allow clock_device_t fs_t:filesystem associate; allow clock_device_t tmpfs_t:filesystem associate; allow clock_device_t tmp_t:filesystem associate; typeattribute cpu_device_t device_node; allow cpu_device_t fs_t:filesystem associate; allow cpu_device_t tmpfs_t:filesystem associate; allow cpu_device_t tmp_t:filesystem associate; typeattribute crypt_device_t device_node; allow crypt_device_t fs_t:filesystem associate; allow crypt_device_t tmpfs_t:filesystem associate; allow crypt_device_t tmp_t:filesystem associate; typeattribute dri_device_t device_node; allow dri_device_t fs_t:filesystem associate; allow dri_device_t tmpfs_t:filesystem associate; allow dri_device_t tmp_t:filesystem associate; typeattribute event_device_t device_node; allow event_device_t fs_t:filesystem associate; allow event_device_t tmpfs_t:filesystem associate; allow event_device_t tmp_t:filesystem associate; typeattribute framebuf_device_t device_node; allow framebuf_device_t fs_t:filesystem associate; allow framebuf_device_t tmpfs_t:filesystem associate; allow framebuf_device_t tmp_t:filesystem associate; typeattribute lvm_control_t device_node; allow lvm_control_t fs_t:filesystem associate; allow lvm_control_t tmpfs_t:filesystem associate; allow lvm_control_t tmp_t:filesystem associate; typeattribute memory_device_t device_node; allow memory_device_t fs_t:filesystem associate; allow memory_device_t tmpfs_t:filesystem associate; allow memory_device_t tmp_t:filesystem associate; neverallow ~memory_raw_read memory_device_t:{ chr_file blk_file } read; neverallow ~memory_raw_write memory_device_t:{ chr_file blk_file } { append write }; typeattribute misc_device_t device_node; allow misc_device_t fs_t:filesystem associate; allow misc_device_t tmpfs_t:filesystem associate; allow misc_device_t tmp_t:filesystem associate; typeattribute mouse_device_t device_node; allow mouse_device_t fs_t:filesystem associate; allow mouse_device_t tmpfs_t:filesystem associate; allow mouse_device_t tmp_t:filesystem associate; typeattribute mtrr_device_t device_node; allow mtrr_device_t fs_t:filesystem associate; allow mtrr_device_t tmpfs_t:filesystem associate; allow mtrr_device_t tmp_t:filesystem associate; typeattribute null_device_t device_node; allow null_device_t fs_t:filesystem associate; allow null_device_t tmpfs_t:filesystem associate; allow null_device_t tmp_t:filesystem associate; typeattribute null_device_t mlstrustedobject; typeattribute power_device_t device_node; allow power_device_t fs_t:filesystem associate; allow power_device_t tmpfs_t:filesystem associate; allow power_device_t tmp_t:filesystem associate; typeattribute printer_device_t device_node; allow printer_device_t fs_t:filesystem associate; allow printer_device_t tmpfs_t:filesystem associate; allow printer_device_t tmp_t:filesystem associate; typeattribute random_device_t device_node; allow random_device_t fs_t:filesystem associate; allow random_device_t tmpfs_t:filesystem associate; allow random_device_t tmp_t:filesystem associate; typeattribute scanner_device_t device_node; allow scanner_device_t fs_t:filesystem associate; allow scanner_device_t tmpfs_t:filesystem associate; allow scanner_device_t tmp_t:filesystem associate; typeattribute sound_device_t device_node; allow sound_device_t fs_t:filesystem associate; allow sound_device_t tmpfs_t:filesystem associate; allow sound_device_t tmp_t:filesystem associate; allow sysfs_t fs_t:filesystem associate; allow sysfs_t noxattrfs:filesystem associate; typeattribute sysfs_t file_type; typeattribute sysfs_t mountpoint; typeattribute sysfs_t filesystem_type; allow sysfs_t self:filesystem associate; typeattribute urandom_device_t device_node; allow urandom_device_t fs_t:filesystem associate; allow urandom_device_t tmpfs_t:filesystem associate; allow urandom_device_t tmp_t:filesystem associate; allow usbfs_t fs_t:filesystem associate; allow usbfs_t noxattrfs:filesystem associate; typeattribute usbfs_t file_type; typeattribute usbfs_t mountpoint; typeattribute usbfs_t filesystem_type; allow usbfs_t self:filesystem associate; typeattribute usbfs_t noxattrfs; typeattribute usb_device_t device_node; allow usb_device_t fs_t:filesystem associate; allow usb_device_t tmpfs_t:filesystem associate; allow usb_device_t tmp_t:filesystem associate; typeattribute v4l_device_t device_node; allow v4l_device_t fs_t:filesystem associate; allow v4l_device_t tmpfs_t:filesystem associate; allow v4l_device_t tmp_t:filesystem associate; typeattribute xserver_misc_device_t device_node; allow xserver_misc_device_t fs_t:filesystem associate; allow xserver_misc_device_t tmpfs_t:filesystem associate; allow xserver_misc_device_t tmp_t:filesystem associate; typeattribute zero_device_t device_node; allow zero_device_t fs_t:filesystem associate; allow zero_device_t tmpfs_t:filesystem associate; allow zero_device_t tmp_t:filesystem associate; typeattribute zero_device_t mlstrustedobject; allow xconsole_device_t fs_t:filesystem associate; allow xconsole_device_t noxattrfs:filesystem associate; typeattribute xconsole_device_t file_type; allow xconsole_device_t tmpfs_t:filesystem associate; allow xconsole_device_t tmp_t:filesystem associate; typeattribute devfs_control_t device_node; allow devfs_control_t fs_t:filesystem associate; allow devfs_control_t tmpfs_t:filesystem associate; allow devfs_control_t tmp_t:filesystem associate; neverallow domain ~domain:process { transition dyntransition }; neverallow { domain -set_curr_context } self:process setcurrent; neverallow { domain unlabeled_t } ~{ domain unlabeled_t }:process *; neverallow ~{ domain unlabeled_t } *:process *; allow file_type self:filesystem associate; allow boot_t fs_t:filesystem associate; allow boot_t noxattrfs:filesystem associate; typeattribute boot_t file_type; allow boot_t fs_t:filesystem associate; allow boot_t noxattrfs:filesystem associate; typeattribute boot_t file_type; typeattribute boot_t mountpoint; allow default_t fs_t:filesystem associate; allow default_t noxattrfs:filesystem associate; allow etc_t fs_t:filesystem associate; allow etc_t noxattrfs:filesystem associate; allow etc_runtime_t fs_t:filesystem associate; allow etc_runtime_t noxattrfs:filesystem associate; allow file_t fs_t:filesystem associate; allow file_t noxattrfs:filesystem associate; allow kernel_t file_t:dir mounton; allow home_root_t fs_t:filesystem associate; allow home_root_t noxattrfs:filesystem associate; allow home_root_t fs_t:filesystem associate; allow home_root_t noxattrfs:filesystem associate; typeattribute home_root_t file_type; typeattribute home_root_t polyparent; allow lost_found_t fs_t:filesystem associate; allow lost_found_t noxattrfs:filesystem associate; allow mnt_t fs_t:filesystem associate; allow mnt_t noxattrfs:filesystem associate; allow modules_object_t fs_t:filesystem associate; allow modules_object_t noxattrfs:filesystem associate; typeattribute modules_object_t file_type; allow no_access_t fs_t:filesystem associate; allow no_access_t noxattrfs:filesystem associate; allow poly_t fs_t:filesystem associate; allow poly_t noxattrfs:filesystem associate; allow readable_t fs_t:filesystem associate; allow readable_t noxattrfs:filesystem associate; allow root_t fs_t:filesystem associate; allow root_t noxattrfs:filesystem associate; allow root_t fs_t:filesystem associate; allow root_t noxattrfs:filesystem associate; typeattribute root_t file_type; typeattribute root_t polyparent; allow kernel_t root_t:dir mounton; allow src_t fs_t:filesystem associate; allow src_t noxattrfs:filesystem associate; allow system_map_t fs_t:filesystem associate; allow system_map_t noxattrfs:filesystem associate; typeattribute system_map_t file_type; allow tmp_t fs_t:filesystem associate; allow tmp_t noxattrfs:filesystem associate; typeattribute tmp_t file_type; allow tmp_t fs_t:filesystem associate; allow tmp_t noxattrfs:filesystem associate; typeattribute tmp_t file_type; typeattribute tmp_t polymember; allow tmp_t tmpfs_t:filesystem associate; typeattribute tmp_t tmpfile; allow tmp_t tmp_t:filesystem associate; allow tmp_t fs_t:filesystem associate; allow tmp_t noxattrfs:filesystem associate; typeattribute tmp_t file_type; typeattribute tmp_t polyparent; allow usr_t fs_t:filesystem associate; allow usr_t noxattrfs:filesystem associate; allow var_t fs_t:filesystem associate; allow var_t noxattrfs:filesystem associate; allow var_lib_t fs_t:filesystem associate; allow var_lib_t noxattrfs:filesystem associate; allow var_lock_t fs_t:filesystem associate; allow var_lock_t noxattrfs:filesystem associate; allow var_run_t fs_t:filesystem associate; allow var_run_t noxattrfs:filesystem associate; allow var_spool_t fs_t:filesystem associate; allow var_spool_t noxattrfs:filesystem associate; typeattribute var_spool_t file_type; allow var_spool_t fs_t:filesystem associate; allow var_spool_t noxattrfs:filesystem associate; typeattribute var_spool_t file_type; typeattribute var_spool_t polymember; allow var_spool_t tmpfs_t:filesystem associate; typeattribute var_spool_t tmpfile; allow var_spool_t tmp_t:filesystem associate; typeattribute fs_t filesystem_type; allow fs_t self:filesystem associate; typeattribute bdev_t filesystem_type; allow bdev_t self:filesystem associate; typeattribute binfmt_misc_fs_t filesystem_type; allow binfmt_misc_fs_t self:filesystem associate; allow binfmt_misc_fs_t fs_t:filesystem associate; allow binfmt_misc_fs_t noxattrfs:filesystem associate; typeattribute binfmt_misc_fs_t file_type; typeattribute binfmt_misc_fs_t mountpoint; typeattribute capifs_t filesystem_type; allow capifs_t self:filesystem associate; typeattribute configfs_t filesystem_type; allow configfs_t self:filesystem associate; typeattribute eventpollfs_t filesystem_type; allow eventpollfs_t self:filesystem associate; typeattribute futexfs_t filesystem_type; allow futexfs_t self:filesystem associate; typeattribute hugetlbfs_t filesystem_type; allow hugetlbfs_t self:filesystem associate; allow hugetlbfs_t fs_t:filesystem associate; allow hugetlbfs_t noxattrfs:filesystem associate; typeattribute hugetlbfs_t file_type; typeattribute hugetlbfs_t mountpoint; typeattribute inotifyfs_t filesystem_type; allow inotifyfs_t self:filesystem associate; typeattribute nfsd_fs_t filesystem_type; allow nfsd_fs_t self:filesystem associate; typeattribute ramfs_t filesystem_type; allow ramfs_t self:filesystem associate; typeattribute romfs_t filesystem_type; allow romfs_t self:filesystem associate; typeattribute rpc_pipefs_t filesystem_type; allow rpc_pipefs_t self:filesystem associate; typeattribute tmpfs_t filesystem_type; allow tmpfs_t self:filesystem associate; allow tmpfs_t fs_t:filesystem associate; allow tmpfs_t noxattrfs:filesystem associate; typeattribute tmpfs_t file_type; allow tmpfs_t fs_t:filesystem associate; allow tmpfs_t noxattrfs:filesystem associate; typeattribute tmpfs_t file_type; typeattribute tmpfs_t mountpoint; allow tmpfs_t noxattrfs:filesystem associate; typeattribute autofs_t filesystem_type; allow autofs_t self:filesystem associate; allow autofs_t fs_t:filesystem associate; allow autofs_t noxattrfs:filesystem associate; typeattribute autofs_t file_type; typeattribute autofs_t mountpoint; typeattribute cifs_t filesystem_type; allow cifs_t self:filesystem associate; typeattribute dosfs_t filesystem_type; allow dosfs_t self:filesystem associate; allow dosfs_t fs_t:filesystem associate; typeattribute iso9660_t filesystem_type; allow iso9660_t self:filesystem associate; allow removable_t noxattrfs:filesystem associate; typeattribute removable_t filesystem_type; allow removable_t self:filesystem associate; allow removable_t fs_t:filesystem associate; allow removable_t noxattrfs:filesystem associate; typeattribute removable_t file_type; typeattribute removable_t usercanread; typeattribute nfs_t filesystem_type; allow nfs_t self:filesystem associate; allow nfs_t fs_t:filesystem associate; allow nfs_t noxattrfs:filesystem associate; typeattribute nfs_t file_type; typeattribute nfs_t mountpoint; neverallow ~can_load_kernmodule self:capability sys_module; role system_r; role sysadm_r; role staff_r; role user_r; role secadm_r; typeattribute kernel_t domain; allow kernel_t self:dir { read getattr lock search ioctl }; allow kernel_t self:lnk_file { read getattr lock ioctl }; allow kernel_t self:file { getattr read write append ioctl lock }; allow kernel_t self:process { fork sigchld }; role secadm_r types kernel_t; role sysadm_r types kernel_t; role user_r types kernel_t; role staff_r types kernel_t; typeattribute kernel_t privrangetrans; role system_r types kernel_t; typeattribute debugfs_t filesystem_type; allow debugfs_t self:filesystem associate; allow debugfs_t self:filesystem associate; allow proc_t fs_t:filesystem associate; allow proc_t noxattrfs:filesystem associate; typeattribute proc_t file_type; typeattribute proc_t mountpoint; typeattribute proc_t filesystem_type; allow proc_t self:filesystem associate; neverallow ~can_receive_kernel_messages proc_kmsg_t:file ~getattr; neverallow { domain -kern_unconfined } proc_kcore_t:file ~getattr; allow sysctl_t fs_t:filesystem associate; allow sysctl_t noxattrfs:filesystem associate; typeattribute sysctl_t file_type; typeattribute sysctl_t mountpoint; allow sysctl_fs_t fs_t:filesystem associate; allow sysctl_fs_t noxattrfs:filesystem associate; typeattribute sysctl_fs_t file_type; typeattribute sysctl_fs_t mountpoint; allow kernel_t self:capability *; allow kernel_t unlabeled_t:dir mounton; allow kernel_t self:process ~{ ptrace setcurrent setexec setfscreate setrlimit execmem execstack execheap }; allow kernel_t self:shm { associate getattr setattr create destroy read write lock unix_read unix_write }; allow kernel_t self:sem { associate getattr setattr create destroy read write unix_read unix_write }; allow kernel_t self:msg { send receive }; allow kernel_t self:msgq { associate getattr setattr create destroy read write enqueue unix_read unix_write }; allow kernel_t self:unix_dgram_socket { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } }; allow kernel_t self:unix_stream_socket { { create { ioctl read getattr write setattr append bind connect getopt setopt shutdown } } listen accept }; allow kernel_t self:unix_dgram_socket sendto; allow kernel_t self:unix_stream_socket connectto; allow kernel_t self:fifo_file { getattr read write append ioctl lock }; allow kernel_t self:sock_file { read getattr lock ioctl }; allow kernel_t self:fd use; allow kernel_t proc_t:dir { read getattr lock search ioctl }; allow kernel_t proc_t:{ lnk_file file } { read getattr lock ioctl }; allow kernel_t proc_net_t:dir { read getattr lock search ioctl }; allow kernel_t proc_net_t:file { read getattr lock ioctl }; allow kernel_t proc_mdstat_t:file { read getattr lock ioctl }; allow kernel_t proc_kcore_t:file getattr; allow kernel_t proc_kmsg_t:file getattr; allow kernel_t sysctl_t:dir { read getattr lock search ioctl }; allow kernel_t sysctl_kernel_t:dir { read getattr lock search ioctl }; allow kernel_t sysctl_kernel_t:file { read getattr lock ioctl }; allow kernel_t unlabeled_t:fifo_file { getattr read write append ioctl lock }; allow kernel_t unlabeled_t:association { sendto recvfrom }; allow kernel_t netif_type:netif rawip_send; allow kernel_t netif_type:netif rawip_recv; allow kernel_t node_type:node rawip_send; allow kernel_t node_type:node rawip_recv; allow kernel_t netif_t:netif rawip_send; allow kernel_t netif_type:netif { tcp_send tcp_recv }; allow kernel_t node_type:node { tcp_send tcp_recv }; allow kernel_t node_t:node rawip_send; allow kernel_t multicast_node_t:node rawip_send; allow kernel_t sysfs_t:dir { read getattr lock search ioctl }; allow kernel_t sysfs_t:{ file lnk_file } { read getattr lock ioctl }; allow kernel_t usbfs_t:dir search; allow kernel_t filesystem_type:filesystem mount; allow kernel_t security_t:dir { read search getattr }; allow kernel_t security_t:file { getattr read write }; typeattribute kernel_t can_load_policy; if(!secure_mode_policyload) { allow kernel_t security_t:security load_policy; auditallow kernel_t security_t:security load_policy; } allow kernel_t device_t:dir { read getattr lock search ioctl }; allow kernel_t device_t:lnk_file { getattr read }; allow kernel_t console_device_t:chr_file { getattr read write append ioctl lock }; allow kernel_t bin_t:dir { read getattr lock search ioctl }; allow kernel_t bin_t:lnk_file { read getattr lock ioctl }; allow kernel_t shell_exec_t:file { { read getattr lock execute ioctl } execute_no_trans }; allow kernel_t sbin_t:dir { read getattr lock search ioctl }; allow kernel_t bin_t:dir { read getattr lock search ioctl }; allow kernel_t bin_t:lnk_file { read getattr lock ioctl }; allow kernel_t bin_t:file { { read getattr lock execute ioctl } execute_no_trans }; allow kernel_t domain:process signal; allow kernel_t proc_t:dir search; allow kernel_t domain:dir search; allow kernel_t root_t:dir { read getattr lock search ioctl }; allow kernel_t root_t:lnk_file { read getattr lock ioctl }; allow kernel_t etc_t:dir { read getattr lock search ioctl }; allow kernel_t home_root_t:dir { read getattr lock search ioctl }; allow kernel_t usr_t:dir { read getattr lock search ioctl }; allow kernel_t usr_t:{ file lnk_file } { read getattr lock ioctl }; typeattribute kernel_t mlsprocread; typeattribute kernel_t mlsprocwrite; allow kernel_t self:capability *; allow kernel_t self:fifo_file { create ioctl read getattr lock write setattr append link unlink rename }; allow kernel_t self:process transition; allow kernel_t self:file { getattr read write append ioctl lock }; allow kernel_t self:nscd *; allow kernel_t self:dbus *; allow kernel_t self:passwd *; allow kernel_t proc_type:{ dir file } *; allow kernel_t sysctl_t:{ dir file } *; allow kernel_t kernel_t:system *; allow kernel_t unlabeled_t:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *; allow kernel_t unlabeled_t:filesystem *; allow kernel_t unlabeled_t:association *; typeattribute kernel_t can_load_kernmodule, can_receive_kernel_messages; typeattribute kernel_t kern_unconfined; allow kernel_t { proc_t proc_net_t }:dir search; allow kernel_t sysctl_type:dir { read getattr lock search ioctl }; allow kernel_t sysctl_type:file { { getattr read write append ioctl lock } setattr }; allow kernel_t node_type:node *; allow kernel_t netif_type:netif *; allow kernel_t port_type:tcp_socket { send_msg recv_msg name_connect }; allow kernel_t port_type:udp_socket { send_msg recv_msg }; allow kernel_t port_type:{ tcp_socket udp_socket rawip_socket } name_bind; allow kernel_t node_type:{ tcp_socket udp_socket rawip_socket } node_bind; allow kernel_t unlabeled_t:association { sendto recvfrom }; allow kernel_t device_node:{ chr_file blk_file } *; allow kernel_t mtrr_device_t:{ dir file } *; allow kernel_t self:capability sys_rawio; typeattribute kernel_t memory_raw_write, memory_raw_read; typeattribute kernel_t unconfined_domain_type; typeattribute kernel_t can_change_process_identity; typeattribute kernel_t can_change_process_role; typeattribute kernel_t can_change_object_identity; typeattribute kernel_t set_curr_context; allow kernel_t domain:{ { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } socket key_socket } *; allow kernel_t domain:fd use; allow kernel_t domain:fifo_file { getattr read write append ioctl lock }; allow kernel_t domain:process ~{ transition dyntransition execmem execstack execheap }; allow kernel_t domain:{ sem msgq shm } *; allow kernel_t domain:msg { send receive }; allow kernel_t domain:dir { read getattr lock search ioctl }; allow kernel_t domain:file { read getattr lock ioctl }; allow kernel_t domain:lnk_file { read getattr lock ioctl }; dontaudit kernel_t domain:dir { read getattr lock search ioctl }; dontaudit kernel_t domain:lnk_file { read getattr lock ioctl }; dontaudit kernel_t domain:file { read getattr lock ioctl }; dontaudit kernel_t domain:sock_file { read getattr lock ioctl }; dontaudit kernel_t domain:fifo_file { read getattr lock ioctl }; allow kernel_t file_type:{ file chr_file } ~execmod; allow kernel_t file_type:{ dir lnk_file sock_file fifo_file blk_file } *; allow kernel_t file_type:filesystem *; allow kernel_t file_type:{ unix_stream_socket unix_dgram_socket } name_bind; if (allow_execmod) { allow kernel_t file_type:file execmod; } allow kernel_t filesystem_type:filesystem *; allow kernel_t filesystem_type:{ dir file lnk_file sock_file fifo_file chr_file blk_file } *; allow kernel_t security_t:dir { getattr search read }; allow kernel_t security_t:file { getattr read write }; typeattribute kernel_t can_load_policy, can_setenforce, can_setsecparam; if(!secure_mode_policyload) { allow kernel_t security_t:security *; auditallow kernel_t security_t:security { load_policy setenforce setbool }; } if (allow_execheap) { allow kernel_t self:process execheap; } if (allow_execmem) { allow kernel_t self:process execmem; } if (allow_execmem && allow_execstack) { allow kernel_t self:process execstack; auditallow kernel_t self:process execstack; } else { } if (allow_execheap) { auditallow kernel_t self:process execheap; } if (allow_execmem) { auditallow kernel_t self:process execmem; } if (read_default_t) { allow kernel_t default_t:dir { read getattr lock search ioctl }; allow kernel_t default_t:file { read getattr lock ioctl }; allow kernel_t default_t:lnk_file { read getattr lock ioctl }; allow kernel_t default_t:sock_file { read getattr lock ioctl }; allow kernel_t default_t:fifo_file { read getattr lock ioctl }; } allow unlabeled_t self:filesystem associate; range_transition getty_t login_exec_t s0 - s0:c0.c255; range_transition init_t xdm_exec_t s0 - s0:c0.c255; range_transition initrc_t crond_exec_t s0 - s0:c0.c255; range_transition initrc_t cupsd_exec_t s0 - s0:c0.c255; range_transition initrc_t sshd_exec_t s0 - s0:c0.c255; range_transition initrc_t udev_exec_t s0 - s0:c0.c255; range_transition initrc_t xdm_exec_t s0 - s0:c0.c255; range_transition kernel_t udev_exec_t s0 - s0:c0.c255; range_transition unconfined_t su_exec_t s0 - s0:c0.c255; range_transition unconfined_t initrc_exec_t s0; typeattribute security_t filesystem_type; allow security_t self:filesystem associate; typeattribute security_t mlstrustedobject; neverallow ~can_load_policy security_t:security load_policy; neverallow ~can_setenforce security_t:security setenforce; neverallow ~can_setsecparam security_t:security setsecparam; typeattribute bsdpty_device_t device_node; allow bsdpty_device_t fs_t:filesystem associate; allow bsdpty_device_t tmpfs_t:filesystem associate; allow bsdpty_device_t tmp_t:filesystem associate; typeattribute console_device_t device_node; allow console_device_t fs_t:filesystem associate; allow console_device_t tmpfs_t:filesystem associate; allow console_device_t tmp_t:filesystem associate; allow devpts_t fs_t:filesystem associate; allow devpts_t noxattrfs:filesystem associate; typeattribute devpts_t file_type; typeattribute devpts_t mountpoint; allow devpts_t tmpfs_t:filesystem associate; allow devpts_t tmp_t:filesystem associate; typeattribute devpts_t filesystem_type; allow devpts_t self:filesystem associate; typeattribute devpts_t ttynode, ptynode; typeattribute devtty_t device_node; allow devtty_t fs_t:filesystem associate; allow devtty_t tmpfs_t:filesystem associate; allow devtty_t tmp_t:filesystem associate; typeattribute devtty_t mlstrustedobject; typeattribute ptmx_t device_node; allow ptmx_t fs_t:filesystem associate; allow ptmx_t tmpfs_t:filesystem associate; allow ptmx_t tmp_t:filesystem associate; typeattribute ptmx_t mlstrustedobject; typeattribute tty_device_t device_node; allow tty_device_t fs_t:filesystem associate; allow tty_device_t tmpfs_t:filesystem associate; allow tty_device_t tmp_t:filesystem associate; typeattribute tty_device_t ttynode; typeattribute usbtty_device_t device_node; allow usbtty_device_t fs_t:filesystem associate; allow usbtty_device_t tmpfs_t:filesystem associate; allow usbtty_device_t tmp_t:filesystem associate; user system_u roles { system_r } level s0 range s0 - s0:c0.c255; user user_u roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255; user root roles { user_r sysadm_r system_r } level s0 range s0 - s0:c0.c255; constrain process transition ( u1 == u2 or t1 == can_change_process_identity ); constrain process transition ( r1 == r2 or t1 == can_change_process_role ); constrain process dyntransition ( u1 == u2 and r1 == r2 ); constrain { dir file lnk_file sock_file fifo_file chr_file blk_file } { create relabelto relabelfrom } ( u1 == u2 or t1 == can_change_object_identity ); constrain { tcp_socket udp_socket rawip_socket netlink_socket packet_socket unix_stream_socket unix_dgram_socket netlink_route_socket netlink_firewall_socket netlink_tcpdiag_socket netlink_nflog_socket netlink_xfrm_socket netlink_selinux_socket netlink_audit_socket netlink_ip6fw_socket netlink_dnrt_socket netlink_kobject_uevent_socket } { create relabelto relabelfrom } ( u1 == u2 or t1 == can_change_object_identity ); sid port system_u:object_r:port_t:s0 sid node system_u:object_r:node_t:s0 sid netif system_u:object_r:netif_t:s0 sid devnull system_u:object_r:null_device_t:s0 sid file system_u:object_r:file_t:s0 sid fs system_u:object_r:fs_t:s0 sid kernel system_u:system_r:kernel_t:s0 sid sysctl system_u:object_r:sysctl_t:s0 sid unlabeled system_u:object_r:unlabeled_t:s0 sid any_socket system_u:object_r:unlabeled_t:s0 sid file_labels system_u:object_r:unlabeled_t:s0 sid icmp_socket system_u:object_r:unlabeled_t:s0 sid igmp_packet system_u:object_r:unlabeled_t:s0 sid init system_u:object_r:unlabeled_t:s0 sid kmod system_u:object_r:unlabeled_t:s0 sid netmsg system_u:object_r:unlabeled_t:s0 sid policy system_u:object_r:unlabeled_t:s0 sid scmp_packet system_u:object_r:unlabeled_t:s0 sid sysctl_modprobe system_u:object_r:unlabeled_t:s0 sid sysctl_fs system_u:object_r:unlabeled_t:s0 sid sysctl_kernel system_u:object_r:unlabeled_t:s0 sid sysctl_net system_u:object_r:unlabeled_t:s0 sid sysctl_net_unix system_u:object_r:unlabeled_t:s0 sid sysctl_vm system_u:object_r:unlabeled_t:s0 sid sysctl_dev system_u:object_r:unlabeled_t:s0 sid tcp_socket system_u:object_r:unlabeled_t:s0 sid security system_u:object_r:security_t:s0 fs_use_xattr ext2 system_u:object_r:fs_t:s0; fs_use_xattr ext3 system_u:object_r:fs_t:s0; fs_use_xattr gfs system_u:object_r:fs_t:s0; fs_use_xattr jfs system_u:object_r:fs_t:s0; fs_use_xattr reiserfs system_u:object_r:fs_t:s0; fs_use_xattr xfs system_u:object_r:fs_t:s0; fs_use_task pipefs system_u:object_r:fs_t:s0; fs_use_task sockfs system_u:object_r:fs_t:s0; fs_use_trans mqueue system_u:object_r:tmpfs_t:s0; fs_use_trans shm system_u:object_r:tmpfs_t:s0; fs_use_trans tmpfs system_u:object_r:tmpfs_t:s0; fs_use_trans devpts system_u:object_r:devpts_t:s0; genfscon proc /mtrr system_u:object_r:mtrr_device_t:s0 genfscon sysfs / system_u:object_r:sysfs_t:s0 genfscon usbfs / system_u:object_r:usbfs_t:s0 genfscon usbdevfs / system_u:object_r:usbfs_t:s0 genfscon rootfs / system_u:object_r:root_t:s0 genfscon bdev / system_u:object_r:bdev_t:s0 genfscon binfmt_misc / system_u:object_r:binfmt_misc_fs_t:s0 genfscon capifs / system_u:object_r:capifs_t:s0 genfscon configfs / system_u:object_r:configfs_t:s0 genfscon eventpollfs / system_u:object_r:eventpollfs_t:s0 genfscon futexfs / system_u:object_r:futexfs_t:s0 genfscon hugetlbfs / system_u:object_r:hugetlbfs_t:s0 genfscon inotifyfs / system_u:object_r:inotifyfs_t:s0 genfscon nfsd / system_u:object_r:nfsd_fs_t:s0 genfscon ramfs / system_u:object_r:ramfs_t:s0 genfscon romfs / system_u:object_r:romfs_t:s0 genfscon cramfs / system_u:object_r:romfs_t:s0 genfscon rpc_pipefs / system_u:object_r:rpc_pipefs_t:s0 genfscon autofs / system_u:object_r:autofs_t:s0 genfscon automount / system_u:object_r:autofs_t:s0 genfscon cifs / system_u:object_r:cifs_t:s0 genfscon smbfs / system_u:object_r:cifs_t:s0 genfscon fat / system_u:object_r:dosfs_t:s0 genfscon msdos / system_u:object_r:dosfs_t:s0 genfscon ntfs / system_u:object_r:dosfs_t:s0 genfscon vfat / system_u:object_r:dosfs_t:s0 genfscon iso9660 / system_u:object_r:iso9660_t:s0 genfscon udf / system_u:object_r:iso9660_t:s0 genfscon nfs / system_u:object_r:nfs_t:s0 genfscon nfs4 / system_u:object_r:nfs_t:s0 genfscon afs / system_u:object_r:nfs_t:s0 genfscon hfsplus / system_u:object_r:nfs_t:s0 genfscon debugfs / system_u:object_r:debugfs_t:s0 genfscon proc / system_u:object_r:proc_t:s0 genfscon proc /sysvipc system_u:object_r:proc_t:s0 genfscon proc /kmsg system_u:object_r:proc_kmsg_t:s0 genfscon proc /kcore system_u:object_r:proc_kcore_t:s0 genfscon proc /mdstat system_u:object_r:proc_mdstat_t:s0 genfscon proc /net system_u:object_r:proc_net_t:s0 genfscon proc /xen system_u:object_r:proc_xen_t:s0 genfscon proc /sys system_u:object_r:sysctl_t:s0 genfscon proc /irq system_u:object_r:sysctl_irq_t:s0 genfscon proc /net/rpc system_u:object_r:sysctl_rpc_t:s0 genfscon proc /sys/fs system_u:object_r:sysctl_fs_t:s0 genfscon proc /sys/kernel system_u:object_r:sysctl_kernel_t:s0 genfscon proc /sys/kernel/modprobe system_u:object_r:sysctl_modprobe_t:s0 genfscon proc /sys/kernel/hotplug system_u:object_r:sysctl_hotplug_t:s0 genfscon proc /sys/net system_u:object_r:sysctl_net_t:s0 genfscon proc /sys/net/unix system_u:object_r:sysctl_net_unix_t:s0 genfscon proc /sys/vm system_u:object_r:sysctl_vm_t:s0 genfscon proc /sys/dev system_u:object_r:sysctl_dev_t:s0 genfscon selinuxfs / system_u:object_r:security_t:s0 portcon udp 7007 system_u:object_r:afs_bos_port_t:s0 portcon tcp 2040 system_u:object_r:afs_fs_port_t:s0 portcon udp 7000 system_u:object_r:afs_fs_port_t:s0 portcon udp 7005 system_u:object_r:afs_fs_port_t:s0 portcon udp 7004 system_u:object_r:afs_ka_port_t:s0 portcon udp 7002 system_u:object_r:afs_pt_port_t:s0 portcon udp 7003 system_u:object_r:afs_vl_port_t:s0 portcon udp 10080 system_u:object_r:amanda_port_t:s0 portcon tcp 10080 system_u:object_r:amanda_port_t:s0 portcon udp 10081 system_u:object_r:amanda_port_t:s0 portcon tcp 10081 system_u:object_r:amanda_port_t:s0 portcon tcp 10082 system_u:object_r:amanda_port_t:s0 portcon tcp 10083 system_u:object_r:amanda_port_t:s0 portcon tcp 10024 system_u:object_r:amavisd_recv_port_t:s0 portcon tcp 10025 system_u:object_r:amavisd_send_port_t:s0 portcon tcp 1720 system_u:object_r:asterisk_port_t:s0 portcon udp 2427 system_u:object_r:asterisk_port_t:s0 portcon udp 2727 system_u:object_r:asterisk_port_t:s0 portcon udp 4569 system_u:object_r:asterisk_port_t:s0 portcon udp 5060 system_u:object_r:asterisk_port_t:s0 portcon tcp 113 system_u:object_r:auth_port_t:s0 portcon tcp 179 system_u:object_r:bgp_port_t:s0 portcon udp 179 system_u:object_r:bgp_port_t:s0 portcon tcp 3310 system_u:object_r:clamd_port_t:s0 portcon udp 4041 system_u:object_r:clockspeed_port_t:s0 portcon udp 512 system_u:object_r:comsat_port_t:s0 portcon tcp 2401 system_u:object_r:cvs_port_t:s0 portcon udp 2401 system_u:object_r:cvs_port_t:s0 portcon udp 6276 system_u:object_r:dcc_port_t:s0 portcon udp 6277 system_u:object_r:dcc_port_t:s0 portcon tcp 1178 system_u:object_r:dbskkd_port_t:s0 portcon udp 68 system_u:object_r:dhcpc_port_t:s0 portcon udp 67 system_u:object_r:dhcpd_port_t:s0 portcon tcp 647 system_u:object_r:dhcpd_port_t:s0 portcon udp 647 system_u:object_r:dhcpd_port_t:s0 portcon tcp 847 system_u:object_r:dhcpd_port_t:s0 portcon udp 847 system_u:object_r:dhcpd_port_t:s0 portcon tcp 2628 system_u:object_r:dict_port_t:s0 portcon tcp 3632 system_u:object_r:distccd_port_t:s0 portcon udp 53 system_u:object_r:dns_port_t:s0 portcon tcp 53 system_u:object_r:dns_port_t:s0 portcon tcp 79 system_u:object_r:fingerd_port_t:s0 portcon tcp 20 system_u:object_r:ftp_data_port_t:s0 portcon tcp 21 system_u:object_r:ftp_port_t:s0 portcon udp 1718 system_u:object_r:gatekeeper_port_t:s0 portcon udp 1719 system_u:object_r:gatekeeper_port_t:s0 portcon tcp 1721 system_u:object_r:gatekeeper_port_t:s0 portcon tcp 7000 system_u:object_r:gatekeeper_port_t:s0 portcon tcp 1213 system_u:object_r:giftd_port_t:s0 portcon tcp 70 system_u:object_r:gopher_port_t:s0 portcon udp 70 system_u:object_r:gopher_port_t:s0 portcon tcp 3128 system_u:object_r:http_cache_port_t:s0 portcon udp 3130 system_u:object_r:http_cache_port_t:s0 portcon tcp 8080 system_u:object_r:http_cache_port_t:s0 portcon tcp 8118 system_u:object_r:http_cache_port_t:s0 portcon tcp 80 system_u:object_r:http_port_t:s0 portcon tcp 443 system_u:object_r:http_port_t:s0 portcon tcp 488 system_u:object_r:http_port_t:s0 portcon tcp 8008 system_u:object_r:http_port_t:s0 portcon tcp 9050 system_u:object_r:http_port_t:s0 portcon tcp 5335 system_u:object_r:howl_port_t:s0 portcon udp 5353 system_u:object_r:howl_port_t:s0 portcon tcp 50000 system_u:object_r:hplip_port_t:s0 portcon tcp 50002 system_u:object_r:hplip_port_t:s0 portcon tcp 9010 system_u:object_r:i18n_input_port_t:s0 portcon tcp 5323 system_u:object_r:imaze_port_t:s0 portcon udp 5323 system_u:object_r:imaze_port_t:s0 portcon tcp 7 system_u:object_r:inetd_child_port_t:s0 portcon udp 7 system_u:object_r:inetd_child_port_t:s0 portcon tcp 9 system_u:object_r:inetd_child_port_t:s0 portcon udp 9 system_u:object_r:inetd_child_port_t:s0 portcon tcp 13 system_u:object_r:inetd_child_port_t:s0 portcon udp 13 system_u:object_r:inetd_child_port_t:s0 portcon tcp 19 system_u:object_r:inetd_child_port_t:s0 portcon udp 19 system_u:object_r:inetd_child_port_t:s0 portcon tcp 37 system_u:object_r:inetd_child_port_t:s0 portcon udp 37 system_u:object_r:inetd_child_port_t:s0 portcon tcp 512 system_u:object_r:inetd_child_port_t:s0 portcon tcp 543 system_u:object_r:inetd_child_port_t:s0 portcon tcp 544 system_u:object_r:inetd_child_port_t:s0 portcon tcp 891 system_u:object_r:inetd_child_port_t:s0 portcon udp 891 system_u:object_r:inetd_child_port_t:s0 portcon tcp 892 system_u:object_r:inetd_child_port_t:s0 portcon udp 892 system_u:object_r:inetd_child_port_t:s0 portcon tcp 2105 system_u:object_r:inetd_child_port_t:s0 portcon tcp 5666 system_u:object_r:inetd_child_port_t:s0 portcon tcp 119 system_u:object_r:innd_port_t:s0 portcon tcp 631 system_u:object_r:ipp_port_t:s0 portcon udp 631 system_u:object_r:ipp_port_t:s0 portcon tcp 6667 system_u:object_r:ircd_port_t:s0 portcon udp 500 system_u:object_r:isakmp_port_t:s0 portcon tcp 5222 system_u:object_r:jabber_client_port_t:s0 portcon tcp 5223 system_u:object_r:jabber_client_port_t:s0 portcon tcp 5269 system_u:object_r:jabber_interserver_port_t:s0 portcon tcp 464 system_u:object_r:kerberos_admin_port_t:s0 portcon udp 464 system_u:object_r:kerberos_admin_port_t:s0 portcon tcp 749 system_u:object_r:kerberos_admin_port_t:s0 portcon tcp 4444 system_u:object_r:kerberos_master_port_t:s0 portcon udp 4444 system_u:object_r:kerberos_master_port_t:s0 portcon tcp 88 system_u:object_r:kerberos_port_t:s0 portcon udp 88 system_u:object_r:kerberos_port_t:s0 portcon tcp 750 system_u:object_r:kerberos_port_t:s0 portcon udp 750 system_u:object_r:kerberos_port_t:s0 portcon udp 517 system_u:object_r:ktalkd_port_t:s0 portcon udp 518 system_u:object_r:ktalkd_port_t:s0 portcon tcp 389 system_u:object_r:ldap_port_t:s0 portcon udp 389 system_u:object_r:ldap_port_t:s0 portcon tcp 636 system_u:object_r:ldap_port_t:s0 portcon udp 636 system_u:object_r:ldap_port_t:s0 portcon tcp 2000 system_u:object_r:mail_port_t:s0 portcon tcp 1234 system_u:object_r:monopd_port_t:s0 portcon tcp 3306 system_u:object_r:mysqld_port_t:s0 portcon tcp 1241 system_u:object_r:nessus_port_t:s0 portcon udp 137 system_u:object_r:nmbd_port_t:s0 portcon udp 138 system_u:object_r:nmbd_port_t:s0 portcon udp 139 system_u:object_r:nmbd_port_t:s0 portcon udp 123 system_u:object_r:ntp_port_t:s0 portcon udp 5000 system_u:object_r:openvpn_port_t:s0 portcon tcp 5988 system_u:object_r:pegasus_http_port_t:s0 portcon tcp 5989 system_u:object_r:pegasus_https_port_t:s0 portcon tcp 106 system_u:object_r:pop_port_t:s0 portcon tcp 109 system_u:object_r:pop_port_t:s0 portcon tcp 110 system_u:object_r:pop_port_t:s0 portcon tcp 143 system_u:object_r:pop_port_t:s0 portcon tcp 220 system_u:object_r:pop_port_t:s0 portcon tcp 993 system_u:object_r:pop_port_t:s0 portcon tcp 995 system_u:object_r:pop_port_t:s0 portcon tcp 1109 system_u:object_r:pop_port_t:s0 portcon udp 111 system_u:object_r:portmap_port_t:s0 portcon tcp 111 system_u:object_r:portmap_port_t:s0 portcon tcp 5432 system_u:object_r:postgresql_port_t:s0 portcon tcp 60000 system_u:object_r:postgrey_port_t:s0 portcon tcp 515 system_u:object_r:printer_port_t:s0 portcon tcp 5703 system_u:object_r:ptal_port_t:s0 portcon udp 4011 system_u:object_r:pxe_port_t:s0 portcon udp 24441 system_u:object_r:pyzor_port_t:s0 portcon udp 1646 system_u:object_r:radacct_port_t:s0 portcon udp 1813 system_u:object_r:radacct_port_t:s0 portcon udp 1645 system_u:object_r:radius_port_t:s0 portcon udp 1812 system_u:object_r:radius_port_t:s0 portcon tcp 2703 system_u:object_r:razor_port_t:s0 portcon tcp 513 system_u:object_r:rlogind_port_t:s0 portcon tcp 953 system_u:object_r:rndc_port_t:s0 portcon udp 520 system_u:object_r:router_port_t:s0 portcon tcp 514 system_u:object_r:rsh_port_t:s0 portcon tcp 873 system_u:object_r:rsync_port_t:s0 portcon udp 873 system_u:object_r:rsync_port_t:s0 portcon tcp 137-139 system_u:object_r:smbd_port_t:s0 portcon tcp 445 system_u:object_r:smbd_port_t:s0 portcon tcp 25 system_u:object_r:smtp_port_t:s0 portcon tcp 465 system_u:object_r:smtp_port_t:s0 portcon tcp 587 system_u:object_r:smtp_port_t:s0 portcon udp 161 system_u:object_r:snmp_port_t:s0 portcon udp 162 system_u:object_r:snmp_port_t:s0 portcon tcp 199 system_u:object_r:snmp_port_t:s0 portcon tcp 783 system_u:object_r:spamd_port_t:s0 portcon tcp 22 system_u:object_r:ssh_port_t:s0 portcon tcp 8000 system_u:object_r:soundd_port_t:s0 portcon tcp 9433 system_u:object_r:soundd_port_t:s0 portcon tcp 901 system_u:object_r:swat_port_t:s0 portcon udp 514 system_u:object_r:syslogd_port_t:s0 portcon tcp 23 system_u:object_r:telnetd_port_t:s0 portcon udp 69 system_u:object_r:tftp_port_t:s0 portcon tcp 8081 system_u:object_r:transproxy_port_t:s0 portcon tcp 540 system_u:object_r:uucpd_port_t:s0 portcon tcp 5900 system_u:object_r:vnc_port_t:s0 portcon tcp 6001 system_u:object_r:xserver_port_t:s0 portcon tcp 6002 system_u:object_r:xserver_port_t:s0 portcon tcp 6003 system_u:object_r:xserver_port_t:s0 portcon tcp 6004 system_u:object_r:xserver_port_t:s0 portcon tcp 6005 system_u:object_r:xserver_port_t:s0 portcon tcp 6006 system_u:object_r:xserver_port_t:s0 portcon tcp 6007 system_u:object_r:xserver_port_t:s0 portcon tcp 6008 system_u:object_r:xserver_port_t:s0 portcon tcp 6009 system_u:object_r:xserver_port_t:s0 portcon tcp 6010 system_u:object_r:xserver_port_t:s0 portcon tcp 6011 system_u:object_r:xserver_port_t:s0 portcon tcp 6012 system_u:object_r:xserver_port_t:s0 portcon tcp 6013 system_u:object_r:xserver_port_t:s0 portcon tcp 6014 system_u:object_r:xserver_port_t:s0 portcon tcp 6015 system_u:object_r:xserver_port_t:s0 portcon tcp 6016 system_u:object_r:xserver_port_t:s0 portcon tcp 6017 system_u:object_r:xserver_port_t:s0 portcon tcp 6018 system_u:object_r:xserver_port_t:s0 portcon tcp 6019 system_u:object_r:xserver_port_t:s0 portcon tcp 8002 system_u:object_r:xen_port_t:s0 portcon tcp 2601 system_u:object_r:zebra_port_t:s0 portcon tcp 8021 system_u:object_r:zope_port_t:s0 portcon tcp 1-1023 system_u:object_r:reserved_port_t:s0 portcon udp 1-1023 system_u:object_r:reserved_port_t:s0 nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:compat_ipv4_node_t:s0 nodecon 0.0.0.0 255.255.255.255 system_u:object_r:inaddr_any_node_t:s0 nodecon fe80:: ffff:ffff:ffff:ffff:: system_u:object_r:link_local_node_t:s0 nodecon 127.0.0.1 255.255.255.255 system_u:object_r:lo_node_t:s0 nodecon ::ffff:0000:0000 ffff:ffff:ffff:ffff:ffff:ffff:: system_u:object_r:mapped_ipv4_node_t:s0 nodecon ff00:: ff00:: system_u:object_r:multicast_node_t:s0 nodecon fec0:: ffc0:: system_u:object_r:site_local_node_t:s0 nodecon :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system_u:object_r:unspec_node_t:s0 libsepol-2.2/tests/policies/test-deps/000077500000000000000000000000001223423440700200505ustar00rootroot00000000000000libsepol-2.2/tests/policies/test-deps/base-metreq.conf000066400000000000000000000164401223423440700231310ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### # TE RULES attribute domain; attribute system; attribute foo; attribute num; attribute num_exec; attribute files; type net_foo_t, foo; type sys_foo_t, foo, system; role system_r; role system_r types sys_foo_t; type user_t, domain; role user_r; role user_r types user_t; type sysadm_t, domain, system; role sysadm_r; role sysadm_r types sysadm_t; type system_t, domain, system, foo; role system_r; role system_r types { system_t sys_foo_t }; type file_t; type file_exec_t, files; type fs_t; # Make this decl easy to find type base_global_decl_t; # Actually used in module tests type type_req_t; attribute attr_req; bool bool_req false; role role_req_r; allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint }; optional { require { type base_optional_1, base_optional_2; } allow base_optional_1 base_optional_2 : file { read write }; } ##################################### # Role Allow allow user_r sysadm_r; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:sys_foo_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) libsepol-2.2/tests/policies/test-deps/base-notmetreq.conf000066400000000000000000000161741223423440700236560ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class msgq inherits ipc { enqueue } class msg { send } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### # TE RULES attribute domain; attribute system; attribute foo; attribute num; attribute num_exec; attribute files; type net_foo_t, foo; type sys_foo_t, foo, system; role system_r; role system_r types sys_foo_t; type user_t, domain; role user_r; role user_r types user_t; type sysadm_t, domain, system; role sysadm_r; role sysadm_r types sysadm_t; type system_t, domain, system, foo; role system_r; role system_r types { system_t sys_foo_t }; type file_t; type file_exec_t, files; type fs_t; type base_optional_1; type base_optional_2; allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint }; optional { require { type base_optional_1, base_optional_2; } allow base_optional_1 base_optional_2 : file { read write }; } ##################################### # Role Allow allow user_r sysadm_r; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:sys_foo_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) libsepol-2.2/tests/policies/test-deps/modreq-attr-global.conf000066400000000000000000000001561223423440700244160ustar00rootroot00000000000000module modreq_attr_global 1.0; require { attribute attr_req; } type mod_global_t; type new_t, attr_req; libsepol-2.2/tests/policies/test-deps/modreq-attr-opt.conf000066400000000000000000000002641223423440700237600ustar00rootroot00000000000000module modreq_attr_opt 1.0; require { class file {read write}; } type mod_global_t; optional { require { attribute attr_req; } type mod_opt_t; type new_t, attr_req; } libsepol-2.2/tests/policies/test-deps/modreq-bool-global.conf000066400000000000000000000002731223423440700243770ustar00rootroot00000000000000module modreq_bool_global 1.0; require { bool bool_req; class file { read write }; } type mod_global_t; type a_t; type b_t; if (bool_req) { allow a_t b_t : file { read write }; } libsepol-2.2/tests/policies/test-deps/modreq-bool-opt.conf000066400000000000000000000003541223423440700237410ustar00rootroot00000000000000module modreq_bool_opt 1.0; require { class file {read write}; } type mod_global_t; optional { require { bool bool_req; } type a_t; type b_t; type mod_opt_t; if (bool_req) { allow a_t b_t : file { read write }; } } libsepol-2.2/tests/policies/test-deps/modreq-obj-global.conf000066400000000000000000000002661223423440700242200ustar00rootroot00000000000000module modreq_obj_global 1.0; require { class sem { create destroy }; } type mod_global_t; type mod_foo_t; type mod_bar_t; allow mod_foo_t mod_bar_t : sem { create destroy }; libsepol-2.2/tests/policies/test-deps/modreq-obj-opt.conf000066400000000000000000000003741223423440700235620ustar00rootroot00000000000000module modreq_obj_global 1.0; require { class file { read }; } type mod_global_t; type mod_foo_t; type mod_bar_t; optional { require { class sem { create destroy }; } type mod_opt_t; allow mod_foo_t mod_bar_t : sem { create destroy }; } libsepol-2.2/tests/policies/test-deps/modreq-perm-global.conf000066400000000000000000000002271223423440700244060ustar00rootroot00000000000000module modreq_perm_global 1.0; require { class msg { send receive }; } type mod_global_t; type a_t; type b_t; allow a_t b_t: msg { send receive }; libsepol-2.2/tests/policies/test-deps/modreq-perm-opt.conf000066400000000000000000000003621223423440700237500ustar00rootroot00000000000000module modreq_perm_opt 1.0; require { class file { read write }; } type mod_global_t; optional { require { class msg { send receive }; } type mod_opt_t; type a_mod_t; type b_mod_t; allow a_mod_t b_mod_t: msg { send receive }; } libsepol-2.2/tests/policies/test-deps/modreq-role-global.conf000066400000000000000000000002361223423440700244040ustar00rootroot00000000000000module modreq_role_global 1.0; require { role role_req_r, user_r; } type mod_global_t; type a_t; # role role_req_r types a_t; allow role_req_r user_r; libsepol-2.2/tests/policies/test-deps/modreq-role-opt.conf000066400000000000000000000002751223423440700237510ustar00rootroot00000000000000module modreq_role_opt 1.0; require { class file {read write}; } type mod_global_t; optional { require { role role_req_r, user_r; } type mod_opt_t; allow role_req_r user_r; } libsepol-2.2/tests/policies/test-deps/modreq-type-global.conf000066400000000000000000000002551223423440700244250ustar00rootroot00000000000000module modreq_type_global 1.0; require { type type_req_t; class file { read write }; } type mod_global_t; type test_t; allow test_t type_req_t : file { read write }; libsepol-2.2/tests/policies/test-deps/modreq-type-opt.conf000066400000000000000000000003271223423440700237670ustar00rootroot00000000000000module modreq_type_opt 1.0; require { type file_t; class file { read write }; } type mod_global_t; optional { require { type type_req_t; } type mod_opt_t; allow type_req_t file_t : file { read write }; }libsepol-2.2/tests/policies/test-deps/module.conf000066400000000000000000000004721223423440700222070ustar00rootroot00000000000000module my_module 1.0; require { bool secure_mode; type system_t, sysadm_t, file_t; attribute domain; role system_r; class file {read write}; } type new_t, domain; role system_r types new_t; allow system_t file_t : file { read write }; if (secure_mode) { allow sysadm_t file_t : file { read write }; } libsepol-2.2/tests/policies/test-deps/small-base.conf000066400000000000000000000161551223423440700227470ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### # TE RULES attribute domain; attribute system; attribute foo; attribute num; attribute num_exec; attribute files; type net_foo_t, foo; type sys_foo_t, foo, system; role system_r types sys_foo_t; type user_t, domain; role user_r types user_t; type sysadm_t, domain, system; role sysadm_r types sysadm_t; type system_t, domain, system, foo; role system_r types { system_t sys_foo_t }; type file_t; type file_exec_t, files; type fs_t; type base_optional_1; type base_optional_2; allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint }; optional { require { type base_optional_1, base_optional_2; } allow base_optional_1 base_optional_2 : file { read write }; } ##################################### # Role Allow allow user_r sysadm_r; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:sys_foo_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) libsepol-2.2/tests/policies/test-expander/000077500000000000000000000000001223423440700207235ustar00rootroot00000000000000libsepol-2.2/tests/policies/test-expander/alias-base.conf000066400000000000000000000154211223423440700235760ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') type enable_optional; # Alias tests type alias_check_1_t; type alias_check_2_t; type alias_check_3_t; typealias alias_check_1_t alias alias_check_1_a; optional { require { type alias_check_2_t; } typealias alias_check_2_t alias alias_check_2_a; } optional { require { type alias_check_3_a; } allow alias_check_3_a enable_optional:file read; } ######## type fs_t; type system_t; type user_t; role system_r; role user_r; role sysadm_r; role system_r types system_t; role user_r types user_t; role sysadm_r types system_t; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:system_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:system_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) libsepol-2.2/tests/policies/test-expander/alias-module.conf000066400000000000000000000001561223423440700241500ustar00rootroot00000000000000module my_module 1.0; require { type alias_check_3_t; } typealias alias_check_3_t alias alias_check_3_a; libsepol-2.2/tests/policies/test-expander/base-base-only.conf000066400000000000000000000007231223423440700243750ustar00rootroot00000000000000class security class file sid kernel common file { read } class file inherits file { entrypoint } class security { compute_av } ifdef(`enable_mls',` sensitivity s0; dominance { s0 } category c0; level s0:c0; mlsconstrain file { read } ( h1 dom h2 ); ') attribute myattr; type mytype_t; role myrole_r; role myrole_r types mytype_t; bool mybool true; gen_user(myuser_u,, myrole_r, s0, s0 - s0:c0) sid kernel gen_context(myuser_u:myrole_r:mytype_t, s0) libsepol-2.2/tests/policies/test-expander/module.conf000066400000000000000000000140671223423440700230670ustar00rootroot00000000000000module my_module 1.0; require { bool allow_ypbind, secure_mode, allow_execstack; type system_t, sysadm_t; class file {read write}; attribute attr_check_base_2, attr_check_base_3; attribute attr_check_base_optional_2; } bool module_1_bool true; if (module_1_bool && allow_ypbind && secure_mode && allow_execstack) { allow system_t sysadm_t : file { read write }; } optional { bool module_1_bool_2 false; require { bool optional_bool_1, optional_bool_2; class file { execute ioctl }; } if (optional_bool_1 && optional_bool_2 || module_1_bool_2) { allow system_t sysadm_t : file {execute ioctl}; } } # Type - attribute mapping test type module_t; attribute attr_check_mod_1; attribute attr_check_mod_2; attribute attr_check_mod_3; attribute attr_check_mod_4; attribute attr_check_mod_5; attribute attr_check_mod_6; attribute attr_check_mod_7; attribute attr_check_mod_8; attribute attr_check_mod_9; attribute attr_check_mod_10; attribute attr_check_mod_11; optional { require { type base_t; } attribute attr_check_mod_optional_1; attribute attr_check_mod_optional_2; attribute attr_check_mod_optional_3; attribute attr_check_mod_optional_4; attribute attr_check_mod_optional_5; attribute attr_check_mod_optional_6; attribute attr_check_mod_optional_7; } optional { require { type does_not_exist_t; } attribute attr_check_mod_optional_disabled_4; attribute attr_check_mod_optional_disabled_7; } type attr_check_base_2_1_t, attr_check_base_2; type attr_check_base_2_2_t; typeattribute attr_check_base_2_2_t attr_check_base_2; type attr_check_base_3_3_t, attr_check_base_3; type attr_check_base_3_4_t; typeattribute attr_check_base_3_4_t attr_check_base_3; optional { require { attribute attr_check_base_5; } type attr_check_base_5_1_t, attr_check_base_5; type attr_check_base_5_2_t; typeattribute attr_check_base_5_2_t attr_check_base_5; } optional { require { attribute attr_check_base_6; } type attr_check_base_6_3_t, attr_check_base_6; type attr_check_base_6_4_t; typeattribute attr_check_base_6_4_t attr_check_base_6; } optional { require { type does_not_exist_t; attribute attr_check_base_8; } type attr_check_base_8_1_t, attr_check_base_8; type attr_check_base_8_2_t; typeattribute attr_check_base_8_2_t attr_check_base_8; } optional { require { type does_not_exist_t; attribute attr_check_base_9; } type attr_check_base_9_3_t, attr_check_base_9; type attr_check_base_9_4_t; typeattribute attr_check_base_9_4_t attr_check_base_9; } optional { require { type does_not_exist_t; attribute attr_check_base_10; } type attr_check_base_10_3_t, attr_check_base_10; type attr_check_base_10_4_t; typeattribute attr_check_base_10_4_t attr_check_base_10; } optional { require { attribute attr_check_base_11; } type attr_check_base_11_3_t, attr_check_base_11; type attr_check_base_11_4_t; typeattribute attr_check_base_11_4_t attr_check_base_11; } type attr_check_base_optional_2_1_t, attr_check_base_optional_2; type attr_check_base_optional_2_2_t; typeattribute attr_check_base_optional_2_2_t attr_check_base_optional_2; optional { require { attribute attr_check_base_optional_5; } type attr_check_base_optional_5_1_t, attr_check_base_optional_5; type attr_check_base_optional_5_2_t; typeattribute attr_check_base_optional_5_2_t attr_check_base_optional_5; } #optional { # require { # attribute attr_check_base_optional_6; # } # type attr_check_base_optional_6_3_t, attr_check_base_optional_6; # type attr_check_base_optional_6_4_t; # typeattribute attr_check_base_optional_6_4_t attr_check_base_optional_6; #} optional { require { type does_not_exist_t; attribute attr_check_base_optional_8; } type attr_check_base_optional_8_1_t, attr_check_base_optional_8; type attr_check_base_optional_8_2_t; typeattribute attr_check_base_optional_8_2_t attr_check_base_optional_8; } type attr_check_mod_2_1_t, attr_check_mod_2; type attr_check_mod_2_2_t; typeattribute attr_check_mod_2_2_t attr_check_mod_2; optional { require { attribute attr_check_mod_5; } type attr_check_mod_5_1_t, attr_check_mod_5; type attr_check_mod_5_2_t; typeattribute attr_check_mod_5_2_t attr_check_mod_5; } optional { require { attribute attr_check_mod_6; } type attr_check_mod_6_3_t, attr_check_mod_6; type attr_check_mod_6_4_t; typeattribute attr_check_mod_6_4_t attr_check_mod_6; } optional { require { type does_not_exist_t; } type attr_check_mod_8_1_t, attr_check_mod_8; type attr_check_mod_8_2_t; typeattribute attr_check_mod_8_2_t attr_check_mod_8; } optional { require { type does_not_exist_t; } type attr_check_mod_9_3_t, attr_check_mod_9; type attr_check_mod_9_4_t; typeattribute attr_check_mod_9_4_t attr_check_mod_9; } optional { require { type does_not_exist_t; } type attr_check_mod_10_3_t, attr_check_mod_10; type attr_check_mod_10_4_t; typeattribute attr_check_mod_10_4_t attr_check_mod_10; } optional { require { type base_t; } type attr_check_mod_11_3_t, attr_check_mod_11; type attr_check_mod_11_4_t; typeattribute attr_check_mod_11_4_t attr_check_mod_11; } #optional { # require { # attribute attr_check_mod_optional_5; # } # type attr_check_mod_optional_5_1_t, attr_check_mod_optional_5; # type attr_check_mod_optional_5_2_t; # typeattribute attr_check_mod_optional_5_2_t attr_check_mod_optional_5; #} #optional { # require { # attribute attr_check_mod_optional_6; # } # type attr_check_mod_optional_6_3_t, attr_check_mod_optional_6; # type attr_check_mod_optional_6_4_t; # typeattribute attr_check_mod_optional_6_4_t attr_check_mod_optional_6; #} optional { require { attribute attr_check_base_optional_disabled_5; } type attr_check_base_optional_disabled_5_1_t, attr_check_base_optional_disabled_5; type attr_check_base_optional_disabled_5_2_t; typeattribute attr_check_base_optional_disabled_5_2_t attr_check_base_optional_disabled_5; } optional { require { type does_not_exist_t; attribute attr_check_base_optional_disabled_8; } type attr_check_base_optional_disabled_8_1_t, attr_check_base_optional_disabled_8; type attr_check_base_optional_disabled_8_2_t; typeattribute attr_check_base_optional_disabled_8_2_t attr_check_base_optional_disabled_8; } libsepol-2.2/tests/policies/test-expander/role-base.conf000066400000000000000000000150241223423440700234450ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') # Role mapping test type role_check_1_1_t; role role_check_1; role role_check_1 types role_check_1_1_t; ######## type fs_t; type system_t; type user_t; role system_r; role user_r; role sysadm_r; role system_r types system_t; role user_r types user_t; role sysadm_r types system_t; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:system_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:system_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) libsepol-2.2/tests/policies/test-expander/role-module.conf000066400000000000000000000002241223423440700240140ustar00rootroot00000000000000module my_module 1.0; require { class file {read write}; role role_check_1; } type role_check_1_2_t; role role_check_1 types role_check_1_2_t; libsepol-2.2/tests/policies/test-expander/small-base.conf000066400000000000000000000313651223423440700236220ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### # TE RULES attribute domain; attribute system; attribute foo; attribute num; attribute num_exec; attribute files; # Type - attribute mapping test # Shorthand tests # 1 = types in base, 2 = types in mod, 3 = types in both # 4 = types in optional in base, 5 = types in optional in mod # 6 = types in optional in both # 7 = types in disabled optional in base # 8 = types in disabled optional in module # 9 = types in disabled optional in both # 10 = types in enabled optional in base, disabled optional in module # 11 = types in disabled optional in base, enabled optional in module attribute attr_check_base_1; attribute attr_check_base_2; attribute attr_check_base_3; attribute attr_check_base_4; attribute attr_check_base_5; attribute attr_check_base_6; attribute attr_check_base_7; attribute attr_check_base_8; attribute attr_check_base_9; attribute attr_check_base_10; attribute attr_check_base_11; optional { require { type module_t; } attribute attr_check_base_optional_1; attribute attr_check_base_optional_2; attribute attr_check_base_optional_3; attribute attr_check_base_optional_4; attribute attr_check_base_optional_5; attribute attr_check_base_optional_6; attribute attr_check_base_optional_8; } optional { require { type does_not_exist_t; } attribute attr_check_base_optional_disabled_5; attribute attr_check_base_optional_disabled_8; } type net_foo_t, foo; type sys_foo_t, foo, system; role system_r; role system_r types sys_foo_t; type user_t, domain; role user_r; role user_r types user_t; type sysadm_t, domain, system; role sysadm_r; role sysadm_r types sysadm_t; type system_t, domain, system, foo; role system_r types { system_t sys_foo_t }; type file_t; type file_exec_t, files; type fs_t; type base_optional_1; type base_optional_2; allow sysadm_t file_exec_t: file { execute read write ioctl lock entrypoint }; optional { require { type base_optional_1, base_optional_2; } allow base_optional_1 base_optional_2 : file { read write }; } # Type - attribute mapping test type base_t; type attr_check_base_1_1_t, attr_check_base_1; type attr_check_base_1_2_t; typeattribute attr_check_base_1_2_t attr_check_base_1; type attr_check_base_3_1_t, attr_check_base_3; type attr_check_base_3_2_t; typeattribute attr_check_base_3_2_t attr_check_base_3; optional { require { attribute attr_check_base_4; } type attr_check_base_4_1_t, attr_check_base_4; type attr_check_base_4_2_t; typeattribute attr_check_base_4_2_t attr_check_base_4; } optional { require { type module_t; } type attr_check_base_6_1_t, attr_check_base_6; type attr_check_base_6_2_t; typeattribute attr_check_base_6_2_t attr_check_base_6; } optional { require { type does_not_exist_t; } type attr_check_base_7_1_t, attr_check_base_7; type attr_check_base_7_2_t; typeattribute attr_check_base_7_2_t attr_check_base_7; } optional { require { type does_not_exist_t; } type attr_check_base_9_1_t, attr_check_base_9; type attr_check_base_9_2_t; typeattribute attr_check_base_9_2_t attr_check_base_9; } optional { require { type module_t; } type attr_check_base_10_1_t, attr_check_base_10; type attr_check_base_10_2_t; typeattribute attr_check_base_10_2_t attr_check_base_10; } optional { require { type does_not_exist_t; } type attr_check_base_11_1_t, attr_check_base_11; type attr_check_base_11_2_t; typeattribute attr_check_base_11_2_t attr_check_base_11; } #optional { # require { # attribute attr_check_base_optional_4; # } # type attr_check_base_optional_4_1_t, attr_check_base_optional_4; # type attr_check_base_optional_4_2_t; # typeattribute attr_check_base_optional_4_2_t attr_check_base_optional_4; #} #optional { # require { # attribute attr_check_base_optional_6; # } # type attr_check_base_optional_6_1_t, attr_check_base_optional_6; # type attr_check_base_optional_6_2_t; # typeattribute attr_check_base_optional_6_2_t attr_check_base_optional_6; #} optional { require { attribute attr_check_mod_4; } type attr_check_mod_4_1_t, attr_check_mod_4; type attr_check_mod_4_2_t; typeattribute attr_check_mod_4_2_t attr_check_mod_4; } optional { require { attribute attr_check_mod_6; } type attr_check_mod_6_1_t, attr_check_mod_6; type attr_check_mod_6_2_t; typeattribute attr_check_mod_6_2_t attr_check_mod_6; } optional { require { type does_not_exist_t; attribute attr_check_mod_7; } type attr_check_mod_7_1_t, attr_check_mod_7; type attr_check_mod_7_2_t; typeattribute attr_check_mod_7_2_t attr_check_mod_7; } optional { require { type does_not_exist_t; attribute attr_check_mod_9; } type attr_check_mod_9_1_t, attr_check_mod_9; type attr_check_mod_9_2_t; typeattribute attr_check_mod_9_2_t attr_check_mod_9; } optional { require { attribute attr_check_mod_10; } type attr_check_mod_10_1_t, attr_check_mod_10; type attr_check_mod_10_2_t; typeattribute attr_check_mod_10_2_t attr_check_mod_10; } optional { require { type does_not_exist_t; attribute attr_check_mod_11; } type attr_check_mod_11_1_t, attr_check_mod_11; type attr_check_mod_11_2_t; typeattribute attr_check_mod_11_2_t attr_check_mod_11; } optional { require { attribute attr_check_mod_optional_4; } type attr_check_mod_optional_4_1_t, attr_check_mod_optional_4; type attr_check_mod_optional_4_2_t; typeattribute attr_check_mod_optional_4_2_t attr_check_mod_optional_4; } optional { require { attribute attr_check_mod_optional_6; } type attr_check_mod_optional_6_1_t, attr_check_mod_optional_6; type attr_check_mod_optional_6_2_t; typeattribute attr_check_mod_optional_6_2_t attr_check_mod_optional_6; } optional { require { type does_not_exist_t; attribute attr_check_mod_optional_7; } type attr_check_mod_optional_7_1_t, attr_check_mod_optional_7; type attr_check_mod_optional_7_2_t; typeattribute attr_check_mod_optional_7_2_t attr_check_mod_optional_7; } optional { require { attribute attr_check_mod_optional_disabled_4; } type attr_check_mod_optional_disabled_4_1_t, attr_check_mod_optional_disabled_4; type attr_check_mod_optional_disabled_4_2_t; typeattribute attr_check_mod_optional_disabled_4_2_t attr_check_mod_optional_disabled_4; } optional { require { type does_not_exist_t; attribute attr_check_mod_optional_disabled_7; } type attr_check_mod_optional_disabled_7_1_t, attr_check_mod_optional_disabled_7; type attr_check_mod_optional_disabled_7_2_t; typeattribute attr_check_mod_optional_disabled_7_2_t attr_check_mod_optional_disabled_7; } ##################################### # Role Allow allow user_r sysadm_r; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:sys_foo_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:sys_foo_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:net_foo_t, s0) libsepol-2.2/tests/policies/test-expander/user-base.conf000066400000000000000000000153071223423440700234660ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') # User mapping test type user_check_1_1_t; type user_check_1_2_t; role user_check_1_1_r; role user_check_1_2_r; role user_check_1_1_r types user_check_1_1_t; role user_check_1_2_r types user_check_1_2_t; ######## type fs_t; type system_t; type user_t; role system_r; role user_r; role sysadm_r; role system_r types system_t; role user_r types user_t; role sysadm_r types system_t; #################################### # Booleans bool allow_ypbind true; bool secure_mode false; bool allow_execheap false; bool allow_execmem true; bool allow_execmod false; bool allow_execstack true; bool optional_bool_1 true; bool optional_bool_2 false; ##################################### # users gen_user(user_check_1,, user_check_1_1_r user_check_1_2_r, s0, s0 - s0:c0.c23) gen_user(system_u,, system_r, s0, s0 - s0:c0.c23) gen_user(root,, user_r sysadm_r, s0, s0 - s0:c0.c23) gen_user(joe,, user_r, s0, s0 - s0:c0.c23) ##################################### # constraints #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(system_u:system_r:system_t, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr ext3 gen_context(system_u:object_r:fs_t, s0); fs_use_xattr reiserfs gen_context(system_u:object_r:fs_t, s0); genfscon proc / gen_context(system_u:object_r:system_t, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 system_u:object_r:net_foo_t:s0 #netifcon lo system_u:object_r:net_foo_t system_u:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 system_u:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(system_u:object_r:system_t, s0) libsepol-2.2/tests/policies/test-expander/user-module.conf000066400000000000000000000001531223423440700240320ustar00rootroot00000000000000module my_module 1.0; require { class file {read write}; ifdef(`enable_mls',` user user_check_1; ') } libsepol-2.2/tests/policies/test-hooks/000077500000000000000000000000001223423440700202405ustar00rootroot00000000000000libsepol-2.2/tests/policies/test-hooks/cmp_policy.conf000066400000000000000000000144031223423440700232470ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### #g_b stands for global base type g_b_type_1; role g_b_role_1 types g_b_type_1; role g_b_role_2 types g_b_type_1; role g_b_role_3 types g_b_type_1; type g_b_type_2; optional { require { type invalid_type; } allow g_b_role_2 g_b_role_3; role_transition g_b_role_2 g_b_type_2 g_b_role_3; } gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23) #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0); genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0 #netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) libsepol-2.2/tests/policies/test-hooks/module_add_role_allow_trans.conf000066400000000000000000000003251223423440700266320ustar00rootroot00000000000000module add_symbol_test 1.0; require { class file { read }; } role role_a_1; role role_a_2; role role_t_1; role role_t_2; type type_rt_1; allow role_a_1 role_a_2; role_transition role_t_1 type_rt_1 role_t_2; libsepol-2.2/tests/policies/test-hooks/module_add_symbols.conf000066400000000000000000000003301223423440700247500ustar00rootroot00000000000000module add_symbol_test 1.0; require { class file { read write }; } type type_add_1; attribute attrib_add_1; role role_add_1; bool bool_add_1 false; ifdef(`enable_mls',`',` user user_add_1 roles { role_add_1 }; ') libsepol-2.2/tests/policies/test-hooks/small-base.conf000066400000000000000000000144031223423440700231310ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### #g_b stands for global base type g_b_type_1; role g_b_role_1 types g_b_type_1; role g_b_role_2 types g_b_type_1; role g_b_role_3 types g_b_type_1; type g_b_type_2; optional { require { type invalid_type; } allow g_b_role_2 g_b_role_3; role_transition g_b_role_2 g_b_type_2 g_b_role_3; } gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23) #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0); genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0 #netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) libsepol-2.2/tests/policies/test-linker/000077500000000000000000000000001223423440700204015ustar00rootroot00000000000000libsepol-2.2/tests/policies/test-linker/module1.conf000066400000000000000000000055751223423440700226320ustar00rootroot00000000000000module linker_test_1 1.0; require { class file { read write }; class lnk_file append; role g_b_role_2; attribute g_b_attr_3; attribute g_b_attr_5; attribute o4_b_attr_1; type g_b_type_3; } type tag_g_m1; #test for type in module and attr in module, added to in module attribute g_m1_attr_1; type g_m1_type_1, g_m1_attr_1; type g_m1_type_2; typeattribute g_m1_type_2 g_m1_attr_1; #add role in module test role g_m1_role_1; role g_m1_role_1 types g_m1_type_1; # test for attr declared in base, added to in module type g_m1_type_3; typeattribute g_m1_type_3 g_b_attr_3; # test for attr declared in base, added to in 2 modules type g_m1_type_4; typeattribute g_m1_type_4 g_b_attr_5; # test for attr declared in base optional, added to in module type g_m1_type_5; typeattribute g_m1_type_5 o4_b_attr_1; # test for attr declared in module, added to in base optional attribute g_m1_attr_2; #add type to base role test role g_b_role_2 types g_m1_type_1; role g_b_role_3; role g_b_role_3 types g_m1_type_2; #add type to base optional role test role o1_b_role_2; role o1_b_role_2 types g_m1_type_1; #optional base role w/ adds in 2 modules role o4_b_role_1; role o4_b_role_1 types g_m1_type_2; # attr a added to in base optional, declared/added to in module, added to in other module attribute g_m1_attr_3; type g_m1_type_6, g_m1_attr_3; # attr a added to in base optional, declared/added in module , added to in other module optional attribute g_m1_attr_4; type g_m1_type_7, g_m1_attr_4; # alias tests typealias g_b_type_3 alias g_m_alias_1; # single boolean in module bool g_m1_bool_1 true; if (g_m1_bool_1) { allow g_m1_type_1 g_m1_type_2 : lnk_file append; } optional { require { type optional_type; attribute g_b_attr_4; attribute o1_b_attr_2; class lnk_file { ioctl }; } type tag_o1_m1; attribute o1_m1_attr_1; type o1_m1_type_2, o1_m1_attr_1; type o1_m1_type_1; role o1_m1_role_1; role o1_m1_role_1 types o1_m1_type_1; type o1_m1_type_3; typeattribute o1_m1_type_3 g_b_attr_4; type o1_m1_type_5; typeattribute o1_m1_type_5 o1_b_attr_2; bool o1_m1_bool_1 false; if (o1_m1_bool_1) { allow o1_m1_type_2 o1_m1_type_1 : lnk_file ioctl; } } optional { require { type optional_type; #role g_b_role_4; // This causes a bug where the role scope doesn't get copied into base } type tag_o2_m1; role g_b_role_4; role g_b_role_4 types g_m1_type_2; } optional { require { attribute g_b_attr_6; } type tag_o3_m1; type o3_m1_type_1; role o3_b_role_1; role o3_b_role_1 types o3_m1_type_1; type o3_m1_type_2, g_b_attr_6; attribute o3_m1_attr_1; # attr a added to in base optional, declared/added in module optional, added to in other module attribute o3_m1_attr_2; type o3_m1_type_3, o3_m1_attr_2; } optional { require { type enable_optional; } type tag_o4_m1; attribute o4_m1_attr_1; type o4_m1_type_1; typeattribute o4_m1_type_1 o4_m1_attr_1; } libsepol-2.2/tests/policies/test-linker/module2.conf000066400000000000000000000023651223423440700226250ustar00rootroot00000000000000module linker_test_2 1.0; require { class file { read write }; class lnk_file { unlink }; attribute g_b_attr_5; attribute g_b_attr_6; attribute g_m1_attr_3; attribute o3_m1_attr_2; } type tag_g_m2; type g_m2_type_1; role g_m2_role_1; role g_m2_role_1 types g_m2_type_1; type g_m2_type_4, g_b_attr_5; type g_m2_type_5, g_b_attr_6; #add types to role declared in base test type g_m2_type_2; role g_b_role_3; role g_b_role_3 types g_m2_type_2; #optional base role w/ adds in 2 modules role o4_b_role_1; role o4_b_role_1 types g_m2_type_1; # attr a added to in base optional, declared/added to in module, added to in other module type g_m2_type_3, g_m1_attr_3; # attr a added to in base optional, declared/added in module optional, added to in other module type g_m2_type_6, o3_m1_attr_2; # cond mapping tests bool g_m2_bool_1 true; bool g_m2_bool_2 false; if (g_m2_bool_1 && g_m2_bool_2) { allow g_m2_type_1 g_m2_type_2 : lnk_file unlink; } optional { require { type optional_type; } type tag_o1_m2; type o1_m2_type_1; role o1_m2_role_1; role o1_m2_role_1 types o1_m2_type_1; } optional { require { attribute g_m1_attr_4; attribute o4_m1_attr_1; } type tag_o2_m2; type o2_m2_type_1, g_m1_attr_4; type o2_m2_type_2, o4_m1_attr_1; } libsepol-2.2/tests/policies/test-linker/small-base.conf000066400000000000000000000207661223423440700233030ustar00rootroot00000000000000# FLASK # # Define the security object classes # class security class process class system class capability # file-related classes class filesystem class file class dir class fd class lnk_file class chr_file class blk_file class sock_file class fifo_file # network-related classes class socket class tcp_socket class udp_socket class rawip_socket class node class netif class netlink_socket class packet_socket class key_socket class unix_stream_socket class unix_dgram_socket # sysv-ipc-related clases class sem class msg class msgq class shm class ipc # FLASK # FLASK # # Define initial security identifiers # sid kernel # FLASK # # Define common prefixes for access vectors # # common common_name { permission_name ... } # # Define a common prefix for file access vectors. # common file { ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton } # # Define a common prefix for socket access vectors. # common socket { # inherited from file ioctl read write create getattr setattr lock relabelfrom relabelto append # socket-specific bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind } # # Define a common prefix for ipc access vectors. # common ipc { create destroy getattr setattr read write associate unix_read unix_write } # # Define the access vectors. # # class class_name [ inherits common_name ] { permission_name ... } # # Define the access vector interpretation for file-related objects. # class filesystem { mount remount unmount getattr relabelfrom relabelto transition associate quotamod quotaget } class dir inherits file { add_name remove_name reparent search rmdir } class file inherits file { execute_no_trans entrypoint } class lnk_file inherits file class chr_file inherits file class blk_file inherits file class sock_file inherits file class fifo_file inherits file class fd { use } # # Define the access vector interpretation for network-related objects. # class socket inherits socket class tcp_socket inherits socket { connectto newconn acceptfrom } class udp_socket inherits socket class rawip_socket inherits socket class node { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send enforce_dest } class netif { tcp_recv tcp_send udp_recv udp_send rawip_recv rawip_send } class netlink_socket inherits socket class packet_socket inherits socket class key_socket inherits socket class unix_stream_socket inherits socket { connectto newconn acceptfrom } class unix_dgram_socket inherits socket # # Define the access vector interpretation for process-related objects # class process { fork transition sigchld # commonly granted from child to parent sigkill # cannot be caught or ignored sigstop # cannot be caught or ignored signull # for kill(pid, 0) signal # all other signals ptrace getsched setsched getsession getpgid setpgid getcap setcap share } # # Define the access vector interpretation for ipc-related objects # class ipc inherits ipc class sem inherits ipc class msgq inherits ipc { enqueue } class msg { send receive } class shm inherits ipc { lock } # # Define the access vector interpretation for the security server. # class security { compute_av transition_sid member_sid sid_to_context context_to_sid load_policy get_sids change_sid get_user_sids } # # Define the access vector interpretation for system operations. # class system { ipc_info avc_toggle nfsd_control bdflush syslog_read syslog_mod syslog_console ichsid } # # Define the access vector interpretation for controling capabilies # class capability { # The capabilities are defined in include/linux/capability.h # Care should be taken to ensure that these are consistent with # those definitions. (Order matters) chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease } ifdef(`enable_mls',` sensitivity s0; # # Define the ordering of the sensitivity levels (least to greatest) # dominance { s0 } # # Define the categories # # Each category has a name and zero or more aliases. # category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; category c8; category c9; category c10; category c11; category c12; category c13; category c14; category c15; category c16; category c17; category c18; category c19; category c20; category c21; category c22; category c23; level s0:c0.c23; mlsconstrain file { write setattr append unlink link rename ioctl lock execute relabelfrom } ( h1 dom h2 ); ') #################################### #################################### ##################################### #g_b stands for global base type enable_optional; #decorative type for finding this decl, every block should have one type tag_g_b; attribute g_b_attr_1; attribute g_b_attr_2; attribute g_b_attr_3; attribute g_b_attr_4; attribute g_b_attr_5; attribute g_b_attr_6; type g_b_type_1, g_b_attr_1; type g_b_type_2, g_b_attr_2; type g_b_type_3; role g_b_role_1; role g_b_role_2; role g_b_role_3; role g_b_role_4; role g_b_role_1 types g_b_type_1; role g_b_role_2 types g_b_type_2; role g_b_role_3 types g_b_type_2; role g_b_role_4 types g_b_type_2; bool g_b_bool_1 false; bool g_b_bool_2 true; allow g_b_type_1 g_b_type_2 : security { compute_av load_policy }; allow g_b_type_1 g_b_type_2 : file *; # test * allow g_b_type_1 g_b_type_2 : process ~ptrace; #test ~ typealias g_b_type_3 alias g_b_alias_1; if (g_b_bool_1) { allow g_b_type_1 g_b_type_2: lnk_file read; } optional { require { type enable_optional; attribute g_m1_attr_2; } type tag_o1_b; attribute o1_b_attr_1; type o1_b_type_1, o1_b_attr_1; bool o1_b_bool_1 true; role o1_b_role_1; role o1_b_role_1 types o1_b_type_1; role o1_b_role_2; role o1_b_role_2 types o1_b_type_1; attribute o1_b_attr_2; type o1_b_type_2, g_m1_attr_2; if (o1_b_bool_1) { allow o1_b_type_1 o1_b_type_2: lnk_file write; } } optional { require { # this should be activated by module 1 type g_m1_type_1; attribute o3_m1_attr_2; } type tag_o2_b; type o2_b_type_1, o3_m1_attr_2; } optional { require { #this block should not come on type invalid_type; } type tag_o3_b; attribute o3_b_attr_1; type o3_b_type_1; bool o3_b_bool_1 true; role o3_b_role_1; role o3_b_role_1 types o3_b_type_1; allow g_b_type_1 invalid_type : sem { create destroy }; } optional { require { # also should be enabled by module 1 type enable_optional; type g_m1_type_1; attribute o3_m1_attr_1; attribute g_m1_attr_3; } type tag_o4_b; attribute o4_b_attr_1; role o4_b_role_1; role o4_b_role_1 types g_m1_type_1; # test for attr declared in module optional, added to in base optional type o4_b_type_1, o3_m1_attr_1; type o4_b_type_2, g_m1_attr_3; } optional { require { attribute g_m1_attr_4; attribute o4_m1_attr_1; } type tag_o5_b; type o5_b_type_1, g_m1_attr_4; type o5_b_type_2, o4_m1_attr_1; } optional { require { type enable_optional; } type tag_o6_b; typealias g_b_type_3 alias g_b_alias_2; } optional { require { type g_m_alias_1; } type tag_o7_b; allow g_m_alias_1 enable_optional:file read; } gen_user(g_b_user_1,, g_b_role_1, s0, s0 - s0:c0.c23) gen_user(g_b_user_2,, g_b_role_1, s0, s0 - s0:c0, c1, c3, c4, c5) #################################### #line 1 "initial_sid_contexts" sid kernel gen_context(g_b_user_1:g_b_role_1:g_b_type_1, s0) ############################################ #line 1 "fs_use" # fs_use_xattr ext2 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr ext3 gen_context(g_b_user_1:object_r:g_b_type_1, s0); fs_use_xattr reiserfs gen_context(g_b_user_1:object_r:g_b_type_1, s0); genfscon proc / gen_context(g_b_user_1:object_r:g_b_type_1, s0) #################################### #line 1 "net_contexts" #portcon tcp 21 g_b_user_1:object_r:net_foo_t:s0 #netifcon lo g_b_user_1:object_r:net_foo_t g_b_user_1:object_r:net_foo_t:s0 # #nodecon 127.0.0.1 255.255.255.255 g_b_user_1:object_r:net_foo_t:s0 nodecon ::1 FFFF:FFFF:FFFF:FFFF:: gen_context(g_b_user_1:object_r:g_b_type_1, s0) libsepol-2.2/tests/test-common.c000066400000000000000000000167661223423440700167620ustar00rootroot00000000000000/* * Author: Joshua Brindle * Chad Sellers * Chris PeBenito * * 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 */ /* This has tests that are common between test suites*/ #include #include void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len) { scope_datum_t *scope; int found; unsigned int i, j; /* make sure it is in global symtab */ if (!hashtab_search(p->symtab[sym_type].table, id)) { fprintf(stderr, "symbol %s not found in table %d\n", id, sym_type); CU_FAIL_FATAL(); } /* make sure its scope is correct */ scope = hashtab_search(p->scope[sym_type].table, id); CU_ASSERT_FATAL(scope != NULL); CU_ASSERT(scope->scope == scope_type); CU_ASSERT(scope->decl_ids_len == len); if (scope->decl_ids_len != len) fprintf(stderr, "sym %s has %d decls, %d expected\n", id, scope->decl_ids_len, len); for (i = 0; i < len; i++) { found = 0; for (j = 0; j < len; j++) { if (decls[i] == scope->decl_ids[j]) found++; } CU_ASSERT(found == 1); } } static int common_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { common_datum_t *d = (common_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_COMMONS][d->s.value - 1] == (char *)key); return 0; } static int class_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { class_datum_t *d = (class_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_CLASSES][d->s.value - 1] == (char *)key); CU_ASSERT(p->class_val_to_struct[d->s.value - 1] == d); return 0; } static int role_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { role_datum_t *d = (role_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_ROLES][d->s.value - 1] == (char *)key); CU_ASSERT(p->role_val_to_struct[d->s.value - 1] == d); return 0; } static int type_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { type_datum_t *d = (type_datum_t *) datum; policydb_t *p = (policydb_t *) data; if (!d->primary) return 0; CU_ASSERT(p->sym_val_to_name[SYM_TYPES][d->s.value - 1] == (char *)key); CU_ASSERT(p->type_val_to_struct[d->s.value - 1] == d); return 0; } static int user_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { user_datum_t *d = (user_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_USERS][d->s.value - 1] == (char *)key); CU_ASSERT(p->user_val_to_struct[d->s.value - 1] == d); return 0; } static int cond_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { cond_bool_datum_t *d = (cond_bool_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_BOOLS][d->s.value - 1] == (char *)key); CU_ASSERT(p->bool_val_to_struct[d->s.value - 1] == d); return 0; } static int level_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { level_datum_t *d = (level_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_LEVELS][d->level->sens - 1] == (char *)key); return 0; } static int cat_test_index(hashtab_key_t key, hashtab_datum_t datum, void *data) { cat_datum_t *d = (cat_datum_t *) datum; policydb_t *p = (policydb_t *) data; CU_ASSERT(p->sym_val_to_name[SYM_CATS][d->s.value - 1] == (char *)key); return 0; } static int (*test_index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *p) = { common_test_index, class_test_index, role_test_index, type_test_index, user_test_index, cond_test_index, level_test_index, cat_test_index,}; void test_policydb_indexes(policydb_t * p) { int i; for (i = 0; i < SYM_NUM; i++) { hashtab_map(p->symtab[i].table, test_index_f[i], p); } } void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor) { type_datum_t *type, *primary; unsigned int my_primary, my_flavor, my_value; type = hashtab_search(p->p_types.table, id); primary = hashtab_search(p->p_types.table, primary_id); CU_ASSERT_PTR_NOT_NULL(type); CU_ASSERT_PTR_NOT_NULL(primary); if (type && primary) { if (mode) { my_flavor = type->flavor; } else { my_flavor = flavor; } if (my_flavor == TYPE_TYPE) { my_primary = 0; my_value = primary->s.value; } else if (my_flavor == TYPE_ALIAS) { my_primary = primary->s.value; CU_ASSERT_NOT_EQUAL(type->s.value, primary->s.value); my_value = type->s.value; } else { CU_FAIL("not an alias"); } CU_ASSERT(type->primary == my_primary); CU_ASSERT(type->flavor == my_flavor); CU_ASSERT(type->s.value == my_value); } } role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags) { ebitmap_node_t *tnode; unsigned int i, j, new, found = 0; role_datum_t *role; if (decl) role = hashtab_search(decl->p_roles.table, id); else role = hashtab_search(p->p_roles.table, id); if (!role) printf("role %s can't be found! \n", id); CU_ASSERT_FATAL(role != NULL); ebitmap_for_each_bit(&role->types.types, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { new = 0; for (j = 0; j < len; j++) { if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) { found++; new = 1; } } if (new == 0) { printf("\nRole %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]); } CU_ASSERT(new == 1); } } CU_ASSERT(found == len); if (found != len) printf("\nrole %s has %d types, %d expected\n", p->sym_val_to_name[SYM_ROLES][role->s.value - 1], found, len); /* roles should never have anything in the negset */ CU_ASSERT(role->types.negset.highbit == 0); CU_ASSERT(role->types.flags == flags); return role; } void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len) { ebitmap_node_t *tnode; int j, new, found = 0; unsigned int i; type_datum_t *attr; if (decl) attr = hashtab_search(decl->p_types.table, id); else attr = hashtab_search(p->p_types.table, id); if (attr == NULL) printf("could not find attr %s in decl %d\n", id, decl->decl_id); CU_ASSERT_FATAL(attr != NULL); CU_ASSERT(attr->flavor == TYPE_ATTRIB); CU_ASSERT(attr->primary == 1); ebitmap_for_each_bit(&attr->types, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { new = 0; for (j = 0; j < len; j++) { if (strcmp(p->sym_val_to_name[SYM_TYPES][i], types[j]) == 0) { found++; new = 1; } } if (new == 0) { printf("\nattr %s had type %s not in types array\n", id, p->sym_val_to_name[SYM_TYPES][i]); } CU_ASSERT(new == 1); } } CU_ASSERT(found == len); if (found != len) printf("\nattr %s has %d types, %d expected\n", id, found, len); } libsepol-2.2/tests/test-common.h000066400000000000000000000066121223423440700167540ustar00rootroot00000000000000/* * Author: Joshua Brindle * Chad Sellers * * 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 */ #ifndef __TEST_COMMON_H__ #define __TEST_COMMON_H__ #include /* p the policy being inspected * id string symbol identifier * sym_type symbol type (eg., SYM_ROLES, SYM_TYPES) * scope_type what scope the role should have (eg., SCOPE_DECL or SCOPE_REQ) * decls integer array of decl id's that we expect the role to have in the scope table * len number of elements in decls * * This is a utility function to test for the symbol's presence in the global symbol table, * the scope table, and that the decl blocks we think this symbol is in are correct */ extern void test_sym_presence(policydb_t * p, char *id, int sym_type, unsigned int scope_type, unsigned int *decls, unsigned int len); /* Test the indexes in the policydb to ensure their correctness. These include * the sym_val_to_name[], class_val_to_struct, role_val_to_struct, type_val_to_struct, * user_val_to_struct, and bool_val_to_struct indexes. */ extern void test_policydb_indexes(policydb_t * p); /* Test alias datum to ensure that it is as expected * * id = the key for the alias * primary_id = the key for its primary * mode: 0 = test the datum according to the flavor value in the call 1 = automatically detect the flavor value and test the datum accordingly * flavor = flavor value if in mode 0 */ extern void test_alias_datum(policydb_t * p, char *id, char *primary_id, char mode, unsigned int flavor); /* p the policy being inspected * id string role identifier * decl the decl block which we are looking in for the role datum * types the array of string types which we expect the role has in its type ebitmap * len number of elements in types * flags the expected flags in the role typeset (eg., * or ~) * * This is a utility function to test whether the type set associated with a role in a specific * avrule decl block matches our expectations */ extern role_datum_t *test_role_type_set(policydb_t * p, char *id, avrule_decl_t * decl, char **types, unsigned int len, unsigned int flags); /* p the policy being inspected * id string attribute identifier * decl the decl block which we are looking in for the attribute datum * types the array of string types which we expect the attribute has in its type ebitmap * len number of elements in types * * This is a utility function to test whether the type set associated with an attribute in a specific * avrule decl block matches our expectations */ extern void test_attr_types(policydb_t * p, char *id, avrule_decl_t * decl, char **types, int len); #endif libsepol-2.2/tests/test-cond.c000066400000000000000000000043751223423440700164060ustar00rootroot00000000000000/* * 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 "test-cond.h" #include "parse_util.h" #include "helpers.h" #include #include #include #include static policydb_t basemod; static policydb_t base_expanded; int cond_test_init(void) { if (policydb_init(&base_expanded)) { fprintf(stderr, "out of memory!\n"); policydb_destroy(&basemod); return -1; } if (test_load_policy(&basemod, POLICY_BASE, 1, "test-cond", "refpolicy-base.conf")) goto cleanup; if (link_modules(NULL, &basemod, NULL, 0, 0)) { fprintf(stderr, "link modules failed\n"); goto cleanup; } if (expand_module(NULL, &basemod, &base_expanded, 0, 1)) { fprintf(stderr, "expand module failed\n"); goto cleanup; } return 0; cleanup: policydb_destroy(&basemod); policydb_destroy(&base_expanded); return -1; } int cond_test_cleanup(void) { policydb_destroy(&basemod); policydb_destroy(&base_expanded); return 0; } static void test_cond_expr_equal(void) { cond_node_t *a, *b; a = base_expanded.cond_list; while (a) { b = base_expanded.cond_list; while (b) { if (a == b) { CU_ASSERT(cond_expr_equal(a, b)); } else { CU_ASSERT(cond_expr_equal(a, b) == 0); } b = b->next; } a = a->next; } } int cond_add_tests(CU_pSuite suite) { if (NULL == CU_add_test(suite, "cond_expr_equal", test_cond_expr_equal)) { return CU_get_error(); } return 0; } libsepol-2.2/tests/test-cond.h000066400000000000000000000020101223423440700163730ustar00rootroot00000000000000/* * 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 */ #ifndef __TEST_COND_H__ #define __TEST_COND_H__ #include int cond_test_init(void); int cond_test_cleanup(void); int cond_add_tests(CU_pSuite suite); #endif libsepol-2.2/tests/test-deps.c000066400000000000000000000237341223423440700164160ustar00rootroot00000000000000/* * 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 "test-deps.h" #include "parse_util.h" #include "helpers.h" #include #include #include /* Tests for dependency checking / handling, specifically: * * 1 type in module global. * 2 attribute in module global. * 3 object class / perm in module global. * 4 boolean in module global. * 5 role in module global. * * 6 type in module optional. * 7 attribute in module optional. * 8 object class / perm in module optional. * 9 boolean in module optional. * 10 role in module optional. * * 11 type in base optional. * 12 attribute in base optional. * 13 object class / perm in base optional. * 14 boolean in base optional. * 15 role in base optional. * * Each of these tests are done with the dependency met and not * met. Additionally, each of the required symbols is used in the * scope it is required. * * In addition to the simple tests, we have test with more complex * modules that test: * * 17 mutual dependencies between two modules. * 18 circular dependency between three modules. * 19 large number of dependencies in a module with a more complex base. * 20 nested optionals with requires. * * Again, each of these tests is done with the requirements met and not * met. */ #include #include #define BASE_MODREQ_TYPE_GLOBAL 0 #define BASE_MODREQ_ATTR_GLOBAL 1 #define BASE_MODREQ_OBJ_GLOBAL 2 #define BASE_MODREQ_BOOL_GLOBAL 3 #define BASE_MODREQ_ROLE_GLOBAL 4 #define BASE_MODREQ_PERM_GLOBAL 5 #define BASE_MODREQ_TYPE_OPT 6 #define BASE_MODREQ_ATTR_OPT 7 #define BASE_MODREQ_OBJ_OPT 8 #define BASE_MODREQ_BOOL_OPT 9 #define BASE_MODREQ_ROLE_OPT 10 #define BASE_MODREQ_PERM_OPT 11 #define NUM_BASES 12 static policydb_t bases_met[NUM_BASES]; static policydb_t bases_notmet[NUM_BASES]; extern int mls; int deps_test_init(void) { int i; /* To test linking we need 1 base per link test and in * order to load them in the init function we have * to keep them all around. Not ideal, but it shouldn't * matter too much. */ for (i = 0; i < NUM_BASES; i++) { if (test_load_policy(&bases_met[i], POLICY_BASE, mls, "test-deps", "base-metreq.conf")) return -1; } for (i = 0; i < NUM_BASES; i++) { if (test_load_policy(&bases_notmet[i], POLICY_BASE, mls, "test-deps", "base-notmetreq.conf")) return -1; } return 0; } int deps_test_cleanup(void) { int i; for (i = 0; i < NUM_BASES; i++) { policydb_destroy(&bases_met[i]); } for (i = 0; i < NUM_BASES; i++) { policydb_destroy(&bases_notmet[i]); } return 0; } /* This function performs testing of the dependency handles for module global * symbols. It is capable of testing 2 scenarios - the dependencies are met * and the dependencies are not met. * * Paramaters: * req_met boolean indicating whether the base policy meets the * requirements for the modules global block. * b index of the base policy in the global bases_met array. * * policy name of the policy module to load for this test. * decl_type name of the unique type found in the module's global * section is to find that avrule_decl. */ static void do_deps_modreq_global(int req_met, int b, char *policy, char *decl_type) { policydb_t *base; policydb_t mod; policydb_t *mods[] = { &mod }; avrule_decl_t *decl; int ret, link_ret; sepol_handle_t *h; /* suppress error reporting - this is because we know that we * are going to get errors and don't want libsepol complaining * about it constantly. */ h = sepol_handle_create(); CU_ASSERT_FATAL(h != NULL); sepol_msg_set_callback(h, NULL, NULL); if (req_met) { base = &bases_met[b]; link_ret = 0; } else { base = &bases_notmet[b]; link_ret = -3; } CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0); /* link the modules and check for the correct return value. */ ret = link_modules(h, base, mods, 1, 0); CU_ASSERT_FATAL(ret == link_ret); policydb_destroy(&mod); if (!req_met) return; decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type); CU_ASSERT_FATAL(decl != NULL); CU_ASSERT(decl->enabled == 1); } /* Test that symbol require statements in the global scope of a module * work correctly. This will cover tests 1 - 5 (described above). * * Each of these policies will require as few symbols as possible to * use the required symbol in addition requiring (for example, the type * test also requires an object class for an allow rule). */ static void deps_modreq_global(void) { /* object classes */ do_deps_modreq_global(1, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_OBJ_GLOBAL, "modreq-obj-global.conf", "mod_global_t"); /* types */ do_deps_modreq_global(1, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_TYPE_GLOBAL, "modreq-type-global.conf", "mod_global_t"); /* attributes */ do_deps_modreq_global(1, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_ATTR_GLOBAL, "modreq-attr-global.conf", "mod_global_t"); /* booleans */ do_deps_modreq_global(1, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_BOOL_GLOBAL, "modreq-bool-global.conf", "mod_global_t"); /* roles */ do_deps_modreq_global(1, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_ROLE_GLOBAL, "modreq-role-global.conf", "mod_global_t"); do_deps_modreq_global(1, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t"); do_deps_modreq_global(0, BASE_MODREQ_PERM_GLOBAL, "modreq-perm-global.conf", "mod_global_t"); } /* This function performs testing of the dependency handles for module optional * symbols. It is capable of testing 2 scenarios - the dependencies are met * and the dependencies are not met. * * Paramaters: * req_met boolean indicating whether the base policy meets the * requirements for the modules global block. * b index of the base policy in the global bases_met array. * * policy name of the policy module to load for this test. * decl_type name of the unique type found in the module's global * section is to find that avrule_decl. */ static void do_deps_modreq_opt(int req_met, int ret_val, int b, char *policy, char *decl_type) { policydb_t *base; policydb_t mod; policydb_t *mods[] = { &mod }; avrule_decl_t *decl; int ret; sepol_handle_t *h; /* suppress error reporting - this is because we know that we * are going to get errors and don't want libsepol complaining * about it constantly. */ h = sepol_handle_create(); CU_ASSERT_FATAL(h != NULL); sepol_msg_set_callback(h, NULL, NULL); if (req_met) { base = &bases_met[b]; } else { base = &bases_notmet[b]; } CU_ASSERT_FATAL(test_load_policy(&mod, POLICY_MOD, mls, "test-deps", policy) == 0); /* link the modules and check for the correct return value. */ ret = link_modules(h, base, mods, 1, 0); CU_ASSERT_FATAL(ret == ret_val); policydb_destroy(&mod); if (ret_val < 0) return; decl = test_find_decl_by_sym(base, SYM_TYPES, decl_type); CU_ASSERT_FATAL(decl != NULL); if (req_met) { CU_ASSERT(decl->enabled == 1); } else { CU_ASSERT(decl->enabled == 0); } } /* Test that symbol require statements in the global scope of a module * work correctly. This will cover tests 6 - 10 (described above). * * Each of these policies will require as few symbols as possible to * use the required symbol in addition requiring (for example, the type * test also requires an object class for an allow rule). */ static void deps_modreq_opt(void) { /* object classes */ do_deps_modreq_opt(1, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_OBJ_OPT, "modreq-obj-opt.conf", "mod_opt_t"); /* types */ do_deps_modreq_opt(1, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_TYPE_OPT, "modreq-type-opt.conf", "mod_opt_t"); /* attributes */ do_deps_modreq_opt(1, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_ATTR_OPT, "modreq-attr-opt.conf", "mod_opt_t"); /* booleans */ do_deps_modreq_opt(1, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_BOOL_OPT, "modreq-bool-opt.conf", "mod_opt_t"); /* roles */ do_deps_modreq_opt(1, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, 0, BASE_MODREQ_ROLE_OPT, "modreq-role-opt.conf", "mod_opt_t"); /* permissions */ do_deps_modreq_opt(1, 0, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t"); do_deps_modreq_opt(0, -3, BASE_MODREQ_PERM_OPT, "modreq-perm-opt.conf", "mod_opt_t"); } int deps_add_tests(CU_pSuite suite) { if (NULL == CU_add_test(suite, "deps_modreq_global", deps_modreq_global)) { return CU_get_error(); } if (NULL == CU_add_test(suite, "deps_modreq_opt", deps_modreq_opt)) { return CU_get_error(); } return 0; } libsepol-2.2/tests/test-deps.h000066400000000000000000000020101223423440700164030ustar00rootroot00000000000000/* * 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 */ #ifndef __TEST_DEPS_H__ #define __TEST_DEPS_H__ #include int deps_test_init(void); int deps_test_cleanup(void); int deps_add_tests(CU_pSuite suite); #endif libsepol-2.2/tests/test-downgrade.c000066400000000000000000000160771223423440700174370ustar00rootroot00000000000000/* * Author: Mary Garvin * * Copyright (C) 2007-2008 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 "test-downgrade.h" #include "parse_util.h" #include "helpers.h" #include #include #include #include #include #include #include #include #define POLICY_BIN_HI "policies/test-downgrade/policy.hi" #define POLICY_BIN_LO "policies/test-downgrade/policy.lo" static policydb_t policydb; /* * Function Name: downgrade_test_init * * Input: None * * Output: None * * Description: Initialize the policydb (policy data base structure) */ int downgrade_test_init(void) { /* Initialize the policydb_t structure */ if (policydb_init(&policydb)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); return -1; } return 0; } /* * Function Name: downgrade_test_cleanup * * Input: None * * Output: None * * Description: Destroys policydb structure */ int downgrade_test_cleanup(void) { policydb_destroy(&policydb); return 0; } /* * Function Name: downgrade_add_tests * * Input: CU_pSuite * * Output: Returns 0 upon success. Returns a CUnit error value on failure. * * Description: Add the given downgrade tests to the downgrade suite. */ int downgrade_add_tests(CU_pSuite suite) { if (CU_add_test(suite, "downgrade", test_downgrade) == NULL) return CU_get_error(); return 0; } /* * Function Name: test_downgrade_possible * * Input: None * * Output: None * * Description: * Tests the backward compatability of MLS and Non-MLS binary policy versions. */ void test_downgrade(void) { if (do_downgrade_test(0) < 0) fprintf(stderr, "\nError during downgrade testing of Non-MLS policy\n"); if (do_downgrade_test(1) < 0) fprintf(stderr, "\nError during downgrade testing of MLS policy\n"); } /* * Function Name: do_downgrade_test * * Input: 0 for Non-MLS policy and 1 for MLS policy downgrade testing * * Output: 0 on success, negative number upon failure * * Description: This function handles the downgrade testing. * A binary policy is read into the policydb structure, the * policy version is decreased by a specific amount, written * back out and then read back in again. The process is * repeated until the minimum policy version is reached. */ int do_downgrade_test(int mls) { policydb_t policydb_tmp; int hi, lo, version; /* Reset policydb for re-use */ policydb_destroy(&policydb); downgrade_test_init(); /* Read in the hi policy from file */ if (read_binary_policy(POLICY_BIN_HI, &policydb) != 0) { fprintf(stderr, "error reading %spolicy binary\n", mls ? "mls " : ""); CU_FAIL("Unable to read the binary policy"); return -1; } /* Change MLS value based on parameter */ policydb.mls = mls ? 1 : 0; for (hi = policydb.policyvers; hi >= POLICYDB_VERSION_MIN; hi--) { /* Stash old version number */ version = policydb.policyvers; /* Try downgrading to each possible version. */ for (lo = hi - 1; lo >= POLICYDB_VERSION_MIN; lo--) { /* Reduce policy version */ policydb.policyvers = lo; /* Write out modified binary policy */ if (write_binary_policy(POLICY_BIN_LO, &policydb) != 0) { /* * Error from MLS to pre-MLS is expected due * to MLS re-implementation in version 19. */ if (mls && lo < POLICYDB_VERSION_MLS) continue; fprintf(stderr, "error writing %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); CU_FAIL("Failed to write downgraded binary policy"); return -1; } /* Make sure we can read back what we wrote. */ if (policydb_init(&policydb_tmp)) { fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); return -1; } if (read_binary_policy(POLICY_BIN_LO, &policydb_tmp) != 0) { fprintf(stderr, "error reading %spolicy binary, version %d (downgraded from %d)\n", mls ? "mls " : "", lo, hi); CU_FAIL("Unable to read downgraded binary policy"); return -1; } policydb_destroy(&policydb_tmp); } /* Restore version number */ policydb.policyvers = version; } return 0; } /* * Function Name: read_binary_policy * * Input: char * which is the path to the file containing the binary policy * * Output: Returns 0 upon success. Upon failure, -1 is returned. * Possible failures are, filename with given path does not exist, * a failure to open the file, or a failure from prolicydb_read * function call. * * Description: Get a filename, open file and read binary policy into policydb * structure. */ int read_binary_policy(const char *path, policydb_t *p) { FILE *in_fp = NULL; struct policy_file f; int rc; /* Open the binary policy file */ if ((in_fp = fopen(path, "rb")) == NULL) { fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); sepol_handle_destroy(f.handle); return -1; } /* Read in the binary policy. */ memset(&f, 0, sizeof(struct policy_file)); f.type = PF_USE_STDIO; f.fp = in_fp; rc = policydb_read(p, &f, 0); sepol_handle_destroy(f.handle); fclose(in_fp); return rc; } /* * Function Name: write_binary_policy * * Input: char * which is the path to the file containing the binary policy * * Output: Returns 0 upon success. Upon failure, -1 is returned. * Possible failures are, filename with given path does not exist, * a failure to open the file, or a failure from prolicydb_read * function call. * * Description: open file and write the binary policy from policydb structure. */ int write_binary_policy(const char *path, policydb_t *p) { FILE *out_fp = NULL; struct policy_file f; sepol_handle_t *handle; int rc; /* We don't want libsepol to print warnings to stderr */ handle = sepol_handle_create(); if (handle == NULL) { fprintf(stderr, "Out of memory!\n"); return -1; } sepol_msg_set_callback(handle, NULL, NULL); /* Open the binary policy file for writing */ if ((out_fp = fopen(path, "w" )) == NULL) { fprintf(stderr, "Unable to open %s: %s\n", path, strerror(errno)); sepol_handle_destroy(f.handle); return -1; } /* Write the binary policy */ memset(&f, 0, sizeof(struct policy_file)); f.type = PF_USE_STDIO; f.fp = out_fp; f.handle = handle; rc = policydb_write(p, &f); sepol_handle_destroy(f.handle); fclose(out_fp); return rc; } libsepol-2.2/tests/test-downgrade.h000066400000000000000000000065601223423440700174400ustar00rootroot00000000000000/* * Author: Mary Garvin * * Copyright (C) 2007-2008 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 */ #ifndef __TEST_DOWNGRADE_H__ #define __TEST_DOWNGRADE_H__ #include #include /* * Function Name: downgrade_test_init * * Input: None * * Output: None * * Description: Initialize the policydb (policy data base structure) */ int downgrade_test_init(void); /* * Function Name: downgrade_test_cleanup * * Input: None * * Output: None * * Description: Destroys policydb structure */ int downgrade_test_cleanup(void); /* * Function Name: downgrade_add_tests * * Input: CU_pSuite * * Output: Returns 0 upon success. Upon failure, a CUnit testing error * value is returned * * Description: Add the given downgrade tests to the downgrade suite. */ int downgrade_add_tests(CU_pSuite suite); /* * Function Name: test_downgrade_possible * * Input: None * * Output: None * * Description: Tests the backward compatability of MLS and Non-MLS binary * policy versions. */ void test_downgrade(void); /* * Function Name: do_downgrade_test * * Input: int that represents a 0 for Non-MLS policy and a * 1 for MLS policy downgrade testing * * Output: (int) 0 on success, negative number upon failure * * Description: This function handles the downgrade testing. A binary policy * is read into the policydb structure, the policy version is * decreased by a specific amount, written back out and then read * back in again. The process is iterative until the minimum * policy version is reached. */ int do_downgrade_test(int mls); /* * Function Name: read_binary_policy * * Input: char * which is the path to the file containing the binary policy * * Output: Returns 0 upon success. Upon failure, -1 is returned. * Possible failures are, filename with given path does not exist, * a failure to open the file, or a failure from prolicydb_read * function call. * * Description: Get a filename, open file and read in the binary policy * into the policydb structure. */ int read_binary_policy(const char *path, policydb_t *); /* * Function Name: write_binary_policy * * Input: char * which is the path to the file containing the binary policy * * Output: Returns 0 upon success. Upon failure, -1 is returned. * Possible failures are, filename with given path does not exist, * a failure to open the file, or a failure from prolicydb_read * function call. * * Description: Get a filename, open file and read in the binary policy * into the policydb structure. */ int write_binary_policy(const char *path, policydb_t *); #endif libsepol-2.2/tests/test-expander-attr-map.c000066400000000000000000000134741223423440700210140ustar00rootroot00000000000000/* * Authors: Chad Sellers * Joshua Brindle * * 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 "test-expander-attr-map.h" #include "test-common.h" #include #include #include extern policydb_t base_expanded2; void test_expander_attr_mapping(void) { /* note that many cases are ommitted because they don't make sense (i.e. declaring in an optional and then using it in the base) or because declare in optional then require in a different optional logic still doesn't work */ char *typesb1[] = { "attr_check_base_1_1_t", "attr_check_base_1_2_t" }; char *typesb2[] = { "attr_check_base_2_1_t", "attr_check_base_2_2_t" }; char *typesb3[] = { "attr_check_base_3_1_t", "attr_check_base_3_2_t", "attr_check_base_3_3_t", "attr_check_base_3_4_t" }; char *typesb4[] = { "attr_check_base_4_1_t", "attr_check_base_4_2_t" }; char *typesb5[] = { "attr_check_base_5_1_t", "attr_check_base_5_2_t" }; char *typesb6[] = { "attr_check_base_6_1_t", "attr_check_base_6_2_t", "attr_check_base_6_3_t", "attr_check_base_6_4_t" }; char *typesbo2[] = { "attr_check_base_optional_2_1_t", "attr_check_base_optional_2_2_t" }; char *typesbo5[] = { "attr_check_base_optional_5_1_t", "attr_check_base_optional_5_2_t" }; char *typesm2[] = { "attr_check_mod_2_1_t", "attr_check_mod_2_2_t" }; char *typesm4[] = { "attr_check_mod_4_1_t", "attr_check_mod_4_2_t" }; char *typesm5[] = { "attr_check_mod_5_1_t", "attr_check_mod_5_2_t" }; char *typesm6[] = { "attr_check_mod_6_1_t", "attr_check_mod_6_2_t", "attr_check_mod_6_3_t", "attr_check_mod_6_4_t" }; char *typesmo2[] = { "attr_check_mod_optional_4_1_t", "attr_check_mod_optional_4_2_t" }; char *typesb10[] = { "attr_check_base_10_1_t", "attr_check_base_10_2_t" }; char *typesb11[] = { "attr_check_base_11_3_t", "attr_check_base_11_4_t" }; char *typesm10[] = { "attr_check_mod_10_1_t", "attr_check_mod_10_2_t" }; char *typesm11[] = { "attr_check_mod_11_3_t", "attr_check_mod_11_4_t" }; test_attr_types(&base_expanded2, "attr_check_base_1", NULL, typesb1, 2); test_attr_types(&base_expanded2, "attr_check_base_2", NULL, typesb2, 2); test_attr_types(&base_expanded2, "attr_check_base_3", NULL, typesb3, 4); test_attr_types(&base_expanded2, "attr_check_base_4", NULL, typesb4, 2); test_attr_types(&base_expanded2, "attr_check_base_5", NULL, typesb5, 2); test_attr_types(&base_expanded2, "attr_check_base_6", NULL, typesb6, 4); test_attr_types(&base_expanded2, "attr_check_base_optional_2", NULL, typesbo2, 2); test_attr_types(&base_expanded2, "attr_check_base_optional_5", NULL, typesbo5, 2); test_attr_types(&base_expanded2, "attr_check_mod_2", NULL, typesm2, 2); test_attr_types(&base_expanded2, "attr_check_mod_4", NULL, typesm4, 2); test_attr_types(&base_expanded2, "attr_check_mod_5", NULL, typesm5, 2); test_attr_types(&base_expanded2, "attr_check_mod_6", NULL, typesm6, 4); test_attr_types(&base_expanded2, "attr_check_mod_optional_4", NULL, typesmo2, 2); test_attr_types(&base_expanded2, "attr_check_base_7", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_base_8", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_base_9", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_base_10", NULL, typesb10, 2); test_attr_types(&base_expanded2, "attr_check_base_11", NULL, typesb11, 2); test_attr_types(&base_expanded2, "attr_check_mod_7", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_mod_8", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_mod_9", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_mod_10", NULL, typesm10, 2); test_attr_types(&base_expanded2, "attr_check_mod_11", NULL, typesm11, 2); test_attr_types(&base_expanded2, "attr_check_base_optional_8", NULL, NULL, 0); test_attr_types(&base_expanded2, "attr_check_mod_optional_7", NULL, NULL, 0); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_1_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_5_2_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_1_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_base_optional_disabled_8_2_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_1_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_4_2_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_1_t")); CU_ASSERT(!hashtab_search((&base_expanded2)->p_types.table, "attr_check_mod_optional_disabled_7_2_t")); } libsepol-2.2/tests/test-expander-attr-map.h000066400000000000000000000017231223423440700210130ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_EXPANDER__ATTR_MAP_H__ #define __TEST_EXPANDER__ATTR_MAP_H__ void test_expander_attr_mapping(void); #endif libsepol-2.2/tests/test-expander-roles.c000066400000000000000000000024331223423440700204040ustar00rootroot00000000000000/* * Authors: Chad Sellers * Joshua Brindle * Chris PeBenito * * 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 "test-expander-roles.h" #include "test-common.h" #include #include #include extern policydb_t role_expanded; void test_expander_role_mapping(void) { char *types1[] = { "role_check_1_1_t", "role_check_1_2_t" }; test_role_type_set(&role_expanded, "role_check_1", NULL, types1, 2, 0); } libsepol-2.2/tests/test-expander-roles.h000066400000000000000000000017721223423440700204160ustar00rootroot00000000000000/* * Author: Joshua Brindle * Author: Chris PeBenito * * 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 */ #ifndef __TEST_EXPANDER_ROLE_H__ #define __TEST_EXPANDER_ROLE_H__ void test_expander_role_mapping(void); #endif libsepol-2.2/tests/test-expander-users.c000066400000000000000000000044121223423440700204200ustar00rootroot00000000000000/* * Authors: Chad Sellers * Joshua Brindle * Chris PeBenito * * 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 "test-expander-users.h" #include #include #include extern policydb_t user_expanded; static void check_user_roles(policydb_t * p, char *user_name, char **role_names, int num_roles) { user_datum_t *user; ebitmap_node_t *tnode; unsigned int i; int j; unsigned char *found; /* array of booleans of roles found */ int extra = 0; /* number of extra roles found */ user = (user_datum_t *) hashtab_search(p->p_users.table, user_name); if (!user) { printf("%s not found\n", user_name); CU_FAIL("user not found"); return; } found = calloc(num_roles, sizeof(unsigned char)); CU_ASSERT_FATAL(found != NULL); ebitmap_for_each_bit(&user->roles.roles, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { extra++; for (j = 0; j < num_roles; j++) { if (strcmp(role_names[j], p->p_role_val_to_name[i]) == 0) { extra--; found[j] += 1; break; } } } } for (j = 0; j < num_roles; j++) { if (found[j] != 1) { printf("role %s associated with user %s %d times\n", role_names[j], user_name, found[j]); CU_FAIL("user mapping failure\n"); } } free(found); CU_ASSERT_EQUAL(extra, 0); } void test_expander_user_mapping(void) { char *roles1[] = { "user_check_1_1_r", "user_check_1_2_r" }; check_user_roles(&user_expanded, "user_check_1", roles1, 2); } libsepol-2.2/tests/test-expander-users.h000066400000000000000000000017721223423440700204330ustar00rootroot00000000000000/* * Author: Joshua Brindle * Author: Chris PeBenito * * 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 */ #ifndef __TEST_EXPANDER_USER_H__ #define __TEST_EXPANDER_USER_H__ void test_expander_user_mapping(void); #endif libsepol-2.2/tests/test-expander.c000066400000000000000000000142701223423440700172640ustar00rootroot00000000000000/* * Authors: Chad Sellers * Joshua Brindle * * 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 */ /* This is where the expander tests should go, including: * - check role, type, bool, user mapping * - add symbols declared in enabled optionals * - do not add symbols declared in disabled optionals * - add rules from enabled optionals * - do not add rules from disabled optionals * - verify attribute mapping * - check conditional expressions for correct mapping */ #include "test-expander.h" #include "parse_util.h" #include "helpers.h" #include "test-common.h" #include "test-expander-users.h" #include "test-expander-roles.h" #include "test-expander-attr-map.h" #include #include #include #include #include #include policydb_t role_expanded; policydb_t user_expanded; policydb_t base_expanded2; static policydb_t basemod; static policydb_t basemod2; static policydb_t mod2; static policydb_t base_expanded; static policydb_t base_only_mod; static policydb_t base_only_expanded; static policydb_t role_basemod; static policydb_t role_mod; static policydb_t user_basemod; static policydb_t user_mod; static policydb_t alias_basemod; static policydb_t alias_mod; static policydb_t alias_expanded; static uint32_t *typemap; extern int mls; /* Takes base, some number of modules, links them, and expands them reads source from myfiles array, which has the base string followed by each module string */ int expander_policy_init(policydb_t * mybase, int num_modules, policydb_t ** mymodules, policydb_t * myexpanded, char **myfiles) { char *filename[num_modules + 1]; int i; for (i = 0; i < num_modules + 1; i++) { filename[i] = calloc(PATH_MAX, sizeof(char)); if (snprintf(filename[i], PATH_MAX, "policies/test-expander/%s%s", myfiles[i], mls ? ".mls" : ".std") < 0) return -1; } if (policydb_init(mybase)) { fprintf(stderr, "out of memory!\n"); return -1; } for (i = 0; i < num_modules; i++) { if (policydb_init(mymodules[i])) { fprintf(stderr, "out of memory!\n"); return -1; } } if (policydb_init(myexpanded)) { fprintf(stderr, "out of memory!\n"); return -1; } mybase->policy_type = POLICY_BASE; mybase->mls = mls; if (read_source_policy(mybase, filename[0], myfiles[0])) { fprintf(stderr, "read source policy failed %s\n", filename[0]); return -1; } for (i = 1; i < num_modules + 1; i++) { mymodules[i - 1]->policy_type = POLICY_MOD; mymodules[i - 1]->mls = mls; if (read_source_policy(mymodules[i - 1], filename[i], myfiles[i])) { fprintf(stderr, "read source policy failed %s\n", filename[i]); return -1; } } if (link_modules(NULL, mybase, mymodules, num_modules, 0)) { fprintf(stderr, "link modules failed\n"); return -1; } if (expand_module(NULL, mybase, myexpanded, 0, 0)) { fprintf(stderr, "expand modules failed\n"); return -1; } return 0; } int expander_test_init(void) { char *small_base_file = "small-base.conf"; char *base_only_file = "base-base-only.conf"; int rc; policydb_t *mymod2; char *files2[] = { "small-base.conf", "module.conf" }; char *role_files[] = { "role-base.conf", "role-module.conf" }; char *user_files[] = { "user-base.conf", "user-module.conf" }; char *alias_files[] = { "alias-base.conf", "alias-module.conf" }; rc = expander_policy_init(&basemod, 0, NULL, &base_expanded, &small_base_file); if (rc != 0) return rc; mymod2 = &mod2; rc = expander_policy_init(&basemod2, 1, &mymod2, &base_expanded2, files2); if (rc != 0) return rc; rc = expander_policy_init(&base_only_mod, 0, NULL, &base_only_expanded, &base_only_file); if (rc != 0) return rc; mymod2 = &role_mod; rc = expander_policy_init(&role_basemod, 1, &mymod2, &role_expanded, role_files); if (rc != 0) return rc; /* Just init the base for now, until we figure out how to separate out mls and non-mls tests since users can't be used in mls module */ mymod2 = &user_mod; rc = expander_policy_init(&user_basemod, 0, NULL, &user_expanded, user_files); if (rc != 0) return rc; mymod2 = &alias_mod; rc = expander_policy_init(&alias_basemod, 1, &mymod2, &alias_expanded, alias_files); if (rc != 0) return rc; return 0; } int expander_test_cleanup(void) { policydb_destroy(&basemod); policydb_destroy(&base_expanded); free(typemap); return 0; } static void test_expander_indexes(void) { test_policydb_indexes(&base_expanded); } static void test_expander_alias(void) { test_alias_datum(&alias_expanded, "alias_check_1_a", "alias_check_1_t", 1, 0); test_alias_datum(&alias_expanded, "alias_check_2_a", "alias_check_2_t", 1, 0); test_alias_datum(&alias_expanded, "alias_check_3_a", "alias_check_3_t", 1, 0); } int expander_add_tests(CU_pSuite suite) { if (NULL == CU_add_test(suite, "expander_indexes", test_expander_indexes)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "expander_attr_mapping", test_expander_attr_mapping)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "expander_role_mapping", test_expander_role_mapping)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "expander_user_mapping", test_expander_user_mapping)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "expander_alias", test_expander_alias)) { CU_cleanup_registry(); return CU_get_error(); } return 0; } libsepol-2.2/tests/test-expander.h000066400000000000000000000020321223423440700172620ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_EXPANDER_H__ #define __TEST_EXPANDER_H__ #include int expander_test_init(void); int expander_test_cleanup(void); int expander_add_tests(CU_pSuite suite); #endif libsepol-2.2/tests/test-linker-cond-map.c000066400000000000000000000120501223423440700204300ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 "helpers.h" #include "test-common.h" #include #include #include #include #include /* Tests for conditionals * Test each cond/bool for these * - boolean copied correctly (state is correct) * - conditional expression is correct * Tests: * - single boolean in base * - single boolean in module * - single boolean in base optional * - single boolean in module optional * - 2 booleans in base * - 2 booleans in module * - 2 booleans in base optional * - 2 booleans in module optional * - 2 booleans, base and module * - 2 booleans, base optional and module * - 2 booleans, base optional and module optional * - 3 booleans, base, base optional, module * - 4 boolean, base, base optional, module, module optional */ typedef struct test_cond_expr { char *bool; uint32_t expr_type; } test_cond_expr_t; void test_cond_expr_mapping(policydb_t * p, avrule_decl_t * d, test_cond_expr_t * bools, int len) { int i; cond_expr_t *expr; CU_ASSERT_FATAL(d->cond_list != NULL); CU_ASSERT_FATAL(d->cond_list->expr != NULL); expr = d->cond_list->expr; for (i = 0; i < len; i++) { CU_ASSERT_FATAL(expr != NULL); CU_ASSERT(expr->expr_type == bools[i].expr_type); if (bools[i].bool) { CU_ASSERT(strcmp(p->sym_val_to_name[SYM_BOOLS][expr->bool - 1], bools[i].bool) == 0); } expr = expr->next; } } void test_bool_state(policydb_t * p, char *bool, int state) { cond_bool_datum_t *b; b = hashtab_search(p->p_bools.table, bool); CU_ASSERT_FATAL(b != NULL); CU_ASSERT(b->state == state); } void base_cond_tests(policydb_t * base) { avrule_decl_t *d; unsigned int decls[1]; test_cond_expr_t bools[2]; /* these tests look at booleans and conditionals in the base only * to ensure that they aren't altered or removed during the link process */ /* bool existance and state, global scope */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"); decls[0] = d->decl_id; test_sym_presence(base, "g_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1); test_bool_state(base, "g_b_bool_1", 0); /* conditional expression mapped correctly */ bools[0].bool = "g_b_bool_1"; bools[0].expr_type = COND_BOOL; test_cond_expr_mapping(base, d, bools, 1); /* bool existance and state, optional scope */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"); decls[0] = d->decl_id; test_sym_presence(base, "o1_b_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1); test_bool_state(base, "o1_b_bool_1", 1); /* conditional expression mapped correctly */ bools[0].bool = "o1_b_bool_1"; bools[0].expr_type = COND_BOOL; test_cond_expr_mapping(base, d, bools, 1); } void module_cond_tests(policydb_t * base) { avrule_decl_t *d; unsigned int decls[1]; test_cond_expr_t bools[3]; /* bool existance and state, module 1 global scope */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"); decls[0] = d->decl_id; test_sym_presence(base, "g_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1); test_bool_state(base, "g_m1_bool_1", 1); /* conditional expression mapped correctly */ bools[0].bool = "g_m1_bool_1"; bools[0].expr_type = COND_BOOL; test_cond_expr_mapping(base, d, bools, 1); /* bool existance and state, module 1 optional scope */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"); decls[0] = d->decl_id; test_sym_presence(base, "o1_m1_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1); test_bool_state(base, "o1_m1_bool_1", 0); /* conditional expression mapped correctly */ bools[0].bool = "o1_m1_bool_1"; bools[0].expr_type = COND_BOOL; test_cond_expr_mapping(base, d, bools, 1); /* bool existance and state, module 2 global scope */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"); decls[0] = d->decl_id; test_sym_presence(base, "g_m2_bool_1", SYM_BOOLS, SCOPE_DECL, decls, 1); test_sym_presence(base, "g_m2_bool_2", SYM_BOOLS, SCOPE_DECL, decls, 1); test_bool_state(base, "g_m2_bool_1", 1); test_bool_state(base, "g_m2_bool_2", 0); /* conditional expression mapped correctly */ bools[0].bool = "g_m2_bool_1"; bools[0].expr_type = COND_BOOL; bools[1].bool = "g_m2_bool_2"; bools[1].expr_type = COND_BOOL; bools[2].bool = NULL; bools[2].expr_type = COND_AND; test_cond_expr_mapping(base, d, bools, 3); } libsepol-2.2/tests/test-linker-cond-map.h000066400000000000000000000020101223423440700204300ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_LINKER_COND_MAP_H__ #define __TEST_LINKER_COND_MAP_H__ extern void base_cond_tests(policydb_t * base); extern void module_cond_tests(policydb_t * base); #endif libsepol-2.2/tests/test-linker-roles.c000066400000000000000000000215671223423440700200730ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 "helpers.h" #include "test-common.h" #include #include #include #include /* Tests for roles: * Test for each of these for * - role in appropriate symtab (global and decl) * - datum in the decl symtab has correct type_set * - scope datum has correct decl ids * - dominates bitmap is correct * Tests: * - role in base, no modules * - role in base optional, no modules * - role a in base, b in module * - role a in base and module (additive) * - role a in base and 2 module * - role a in base optional, b in module * - role a in base, b in module optional * - role a in base optional, b in module optional * - role a in base optional and module * - role a in base and module optional * - role a in base optional and module optional * - role a in base optional and 2 modules * - role a and b in base, b dom a, are types correct (TODO) */ /* this simply tests whether the passed in role only has its own * value in its dominates ebitmap */ static void only_dominates_self(policydb_t * p, role_datum_t * role) { ebitmap_node_t *tnode; unsigned int i; int found = 0; ebitmap_for_each_bit(&role->dominates, tnode, i) { if (ebitmap_node_get_bit(tnode, i)) { found++; CU_ASSERT(i == role->s.value - 1); } } CU_ASSERT(found == 1); } void base_role_tests(policydb_t * base) { avrule_decl_t *decl; role_datum_t *role; unsigned int decls[2]; char *types[2]; /* These tests look at roles in the base only, the desire is to ensure that * roles are not destroyed or otherwise removed during the link process */ /**** test for g_b_role_1 in base and decl 1 (global) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1); /* make sure it has the correct type set (g_b_type_1, no negset, no flags) */ types[0] = "g_b_type_1"; role = test_role_type_set(base, "g_b_role_1", NULL, types, 1, 0); /* This role should only dominate itself */ only_dominates_self(base, role); /**** test for o1_b_role_1 in optional (decl 2) ****/ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"); decls[0] = decl->decl_id; test_sym_presence(base, "o1_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 1); /* make sure it has the correct type set (o1_b_type_1, no negset, no flags) */ types[0] = "o1_b_type_1"; role = test_role_type_set(base, "o1_b_role_1", decl, types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); } void module_role_tests(policydb_t * base) { role_datum_t *role; avrule_decl_t *decl; unsigned int decls[2]; char *types[3]; /* These tests are run when the base is linked with 2 modules, * They should test whether the roles get copied correctly from the * modules into the base */ /**** test for role in module 1 (global) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1); /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */ types[0] = "g_m1_type_1"; role = test_role_type_set(base, "g_m1_role_1", NULL, types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for role in module 1 (optional) ****/ decl = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"); decls[0] = decl->decl_id; test_sym_presence(base, "o1_m1_role_1", SYM_ROLES, SCOPE_DECL, decls, 1); /* make sure it has the correct type set (o1_m1_type_1, no negset, no flags) */ types[0] = "o1_m1_type_1"; role = test_role_type_set(base, "o1_m1_role_1", decl, types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); /* These test whether the type sets are copied to the right place and * correctly unioned when they should be */ /**** test for type added to base role in module 1 (global) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2); /* make sure it has the correct type set (g_m1_type_1, no negset, no flags) */ types[0] = "g_b_type_2"; /* added in base when declared */ types[1] = "g_m1_type_1"; /* added in module */ role = test_role_type_set(base, "g_b_role_2", NULL, types, 2, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for type added to base role in module 1 & 2 (global) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id; test_sym_presence(base, "g_b_role_3", SYM_ROLES, SCOPE_DECL, decls, 3); /* make sure it has the correct type set (g_b_type_2, g_m1_type_2, g_m2_type_2, no negset, no flags) */ types[0] = "g_b_type_2"; /* added in base when declared */ types[1] = "g_m1_type_2"; /* added in module 1 */ types[2] = "g_m2_type_2"; /* added in module 2 */ role = test_role_type_set(base, "g_b_role_3", NULL, types, 3, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for role in base optional and module 1 (additive) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "o1_b_role_2", SYM_ROLES, SCOPE_DECL, decls, 2); /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */ types[0] = "g_m1_type_1"; role = test_role_type_set(base, "o1_b_role_2", NULL, types, 1, 0); types[0] = "o1_b_type_1"; role = test_role_type_set(base, "o1_b_role_2", test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"), types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for role in base and module 1 optional (additive) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"))->decl_id; test_sym_presence(base, "g_b_role_4", SYM_ROLES, SCOPE_DECL, decls, 2); /* this one will have 2 type sets, one in the global symtab and one in the base optional 1 */ types[0] = "g_b_type_2"; role = test_role_type_set(base, "g_b_role_4", NULL, types, 1, 0); types[0] = "g_m1_type_2"; role = test_role_type_set(base, "g_b_role_4", test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m1"), types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for role in base and module 1 optional (additive) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id; test_sym_presence(base, "o3_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 2); /* this one will have 2 type sets, one in the 3rd base optional and one in the 3rd module optional */ types[0] = "o3_b_type_1"; role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_b"), types, 1, 0); types[0] = "o3_m1_type_1"; role = test_role_type_set(base, "o3_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"), types, 1, 0); /* and only dominates itself */ only_dominates_self(base, role); /**** test for role in base and module 1 optional (additive) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id; decls[1] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; decls[2] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m2"))->decl_id; test_sym_presence(base, "o4_b_role_1", SYM_ROLES, SCOPE_DECL, decls, 3); /* this one will have 2 type sets, one in the global symtab (with both module types) and one in the 4th optional of base */ types[0] = "g_m1_type_1"; role = test_role_type_set(base, "o4_b_role_1", test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"), types, 1, 0); types[0] = "g_m2_type_1"; types[1] = "g_m1_type_2"; role = test_role_type_set(base, "o4_b_role_1", NULL, types, 2, 0); /* and only dominates itself */ only_dominates_self(base, role); } libsepol-2.2/tests/test-linker-roles.h000066400000000000000000000020501223423440700200620ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_LINKER_ROLES_H__ #define __TEST_LINKER_ROLES_H__ #include extern void base_role_tests(policydb_t * base); extern void module_role_tests(policydb_t * base); #endif libsepol-2.2/tests/test-linker-types.c000066400000000000000000000352031223423440700201030ustar00rootroot00000000000000/* * Author: Joshua Brindle * Chad Sellers * * 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 "helpers.h" #include "test-common.h" #include #include #include #include /* Tests for types: * Test for each of these for * - type in appropriate symtab (global and decl) * - datum in the decl symtab has correct type bitmap (if attr) * - primary is set correctly * - scope datum has correct decl ids * Tests: * - type in base, no modules * - type in base optional, no modules * - type a in base, b in module * - type a in base optional, b in module * - type a in base, b in module optional * - type a in base optional, b in module optional * - attr in base, no modules * - attr in base optional, no modules * - attr a in base, b in module * - attr a in base optional, b in module * - attr a in base, b in module optional * - attr a in base optional, b in module optional * - attr a declared in base, added to in module * - attr a declared in base, added to in module optional * - attr a declared in base, added to in 2 modules * - attr a declared in base, added to in 2 modules (optional and global) * - attr a declared in base optional, added to in module * - attr a declared in base optional, added to in module optional * - attr a added to in base optional, declared in module * - attr a added to in base optional, declared in module optional * - attr a added to in base optional, declared in module, added to in other module * - attr a added to in base optional, declared in module optional, added to in other module * - attr a added to in base optional, declared in module , added to in other module optional * - attr a added to in base optional, declared in module optional, added to in other module optional * - alias in base of primary type in base, no modules * - alias in base optional of primary type in base, no modules * - alias in base optional of primary type in base optional * - alias in module of primary type in base * - alias in module optional of primary type in base * - alias in module optional of primary type in base optional * - alias in module of primary type in module * - alias in module optional of primary type in module * - alias in module optional of primary type in module optional * - alias a in base, b in module, primary type in base * - alias a in base, b in module, primary type in module * - alias a in base optional, b in module, primary type in base * - alias a in base optional, b in module, primary type in module * - alias a in base, b in module optional, primary type in base * - alias a in base, b in module optional, primary type in module * - alias a in base optional, b in module optional, primary type in base * - alias a in base optional, b in module optional, primary type in module * - alias a in base, required in module, primary type in base * - alias a in base, required in base optional, primary type in base * - alias a in base, required in module optional, primary type in base * - alias a in module, required in base optional, primary type in base * - alias a in module, required in module optional, primary type in base * - alias a in base optional, required in module, primary type in base * - alias a in base optional, required in different base optional, primary type in base * - alias a in base optional, required in module optional, primary type in base * - alias a in module optional, required in base optional, primary type in base * - alias a in module optional, required in module optional, primary type in base * - alias a in module, required in base optional, primary type in module * - alias a in module, required in module optional, primary type in module * - alias a in base optional, required in module, primary type in module * - alias a in base optional, required in different base optional, primary type in module * - alias a in base optional, required in module optional, primary type in module * - alias a in module optional, required in base optional, primary type in module * - alias a in module optional, required in module optional, primary type in module */ /* Don't pass in decls from global blocks since symbols aren't stored in their symtab */ static void test_type_datum(policydb_t * p, char *id, unsigned int *decls, int len, unsigned int primary) { int i; unsigned int value; type_datum_t *type; /* just test the type datums for each decl to see if it is what we expect */ type = hashtab_search(p->p_types.table, id); CU_ASSERT_FATAL(type != NULL); CU_ASSERT(type->primary == primary); CU_ASSERT(type->flavor == TYPE_TYPE); value = type->s.value; for (i = 0; i < len; i++) { type = hashtab_search(p->decl_val_to_struct[decls[i] - 1]->p_types.table, id); CU_ASSERT_FATAL(type != NULL); CU_ASSERT(type->primary == primary); CU_ASSERT(type->flavor == TYPE_TYPE); CU_ASSERT(type->s.value == value); } } void base_type_tests(policydb_t * base) { unsigned int decls[2]; char *types[2]; /* These tests look at types in the base only, the desire is to ensure that * types are not destroyed or otherwise removed during the link process. * if this happens these tests won't work anyway since we are using types to * mark blocks */ /**** test for g_b_type_1 in base and decl 1 (global) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_type_datum(base, "g_b_type_1", NULL, 0, 1); /* this attr is in the same decl as the type */ test_sym_presence(base, "g_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_b_type_1"; test_attr_types(base, "g_b_attr_1", NULL, types, 1); /**** test for o1_b_type_1 in optional (decl 2) ****/ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id; test_sym_presence(base, "o1_b_type_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_type_datum(base, "o1_b_type_1", NULL, 0, 1); /* this attr is in the same decl as the type */ test_sym_presence(base, "o1_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "o1_b_type_1"; test_attr_types(base, "o1_b_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1); /* tests for aliases */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_alias_datum(base, "g_b_alias_1", "g_b_type_3", 1, 0); decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o6_b"))->decl_id; test_sym_presence(base, "g_b_alias_2", SYM_TYPES, SCOPE_DECL, decls, 1); test_alias_datum(base, "g_b_alias_2", "g_b_type_3", 1, 0); } void module_type_tests(policydb_t * base) { unsigned int decls[2]; char *types[2]; avrule_decl_t *d; /* These tests look at types that were copied from modules or attributes * that were modified and declared in modules and base. These apply to * declarations and modifications in and out of optionals. These tests * should ensure that types and attributes are correctly copied from modules * and that attribute type sets are correctly copied and mapped. */ /* note: scope for attributes is currently smashed if the attribute is declared * somewhere so the scope test only looks at global, the type bitmap test looks * at the appropriate decl symtab */ /* test for type in module 1 (global) */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_type_datum(base, "g_m1_type_1", NULL, 0, 1); /* attr has is in the same decl as the above type */ test_sym_presence(base, "g_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_1"; types[1] = "g_m1_type_2"; test_attr_types(base, "g_m1_attr_1", NULL, types, 2); /* test for type in module 1 (optional) */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id; test_sym_presence(base, "o1_m1_type_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_type_datum(base, "o1_m1_type_1", NULL, 0, 1); /* attr has is in the same decl as the above type */ test_sym_presence(base, "o1_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "o1_m1_type_2"; test_attr_types(base, "o1_m1_attr_1", base->decl_val_to_struct[decls[0] - 1], types, 1); /* test for attr declared in base, added to in module (global). * Since these are both global it'll be merged in the main symtab */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_3"; test_attr_types(base, "g_b_attr_3", NULL, types, 1); /* test for attr declared in base, added to in module (optional). */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1); decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"))->decl_id; types[0] = "o1_m1_type_3"; test_attr_types(base, "g_b_attr_4", base->decl_val_to_struct[decls[0] - 1], types, 1); /* test for attr declared in base, added to in 2 modules (global). (merged in main symtab) */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_attr_5", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_4"; types[1] = "g_m2_type_4"; test_attr_types(base, "g_b_attr_5", NULL, types, 2); /* test for attr declared in base, added to in 2 modules (optional/global). */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_b"))->decl_id; test_sym_presence(base, "g_b_attr_6", SYM_TYPES, SCOPE_DECL, decls, 1); /* module 2 was global to its type is in main symtab */ types[0] = "g_m2_type_5"; test_attr_types(base, "g_b_attr_6", NULL, types, 1); d = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1")); types[0] = "o3_m1_type_2"; test_attr_types(base, "g_b_attr_6", d, types, 1); /* test for attr declared in base optional, added to in module (global). */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"))->decl_id; test_sym_presence(base, "o4_b_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_5"; test_attr_types(base, "o4_b_attr_1", NULL, types, 1); /* test for attr declared in base optional, added to in module (optional). */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"))->decl_id; test_sym_presence(base, "o1_b_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1); d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_m1"); types[0] = "o1_m1_type_5"; test_attr_types(base, "o1_b_attr_2", d, types, 1); /* test for attr declared in module, added to in base optional */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1); d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o1_b"); types[0] = "o1_b_type_2"; test_attr_types(base, "g_m1_attr_2", d, types, 1); /* test for attr declared in module optional, added to in base optional */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"))->decl_id; test_sym_presence(base, "o3_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"); types[0] = "o4_b_type_1"; test_attr_types(base, "o3_m1_attr_1", d, types, 1); /* attr a added to in base optional, declared/added to in module, added to in other module */ /* first the module declare/add and module 2 add (since its global it'll be in the main symtab */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m1_attr_3", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_6"; types[1] = "g_m2_type_3"; test_attr_types(base, "g_m1_attr_3", NULL, types, 2); /* base add */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_b"); types[0] = "o4_b_type_2"; test_attr_types(base, "g_m1_attr_3", d, types, 1); /* attr a added to in base optional, declared/added in module optional, added to in other module */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o3_m1"); decls[0] = d->decl_id; test_sym_presence(base, "o3_m1_attr_2", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "o3_m1_type_3"; test_attr_types(base, "o3_m1_attr_2", d, types, 1); /* module 2's type will be in the main symtab */ types[0] = "g_m2_type_6"; test_attr_types(base, "o3_m1_attr_2", NULL, types, 1); /* base add */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_b"); types[0] = "o2_b_type_1"; test_attr_types(base, "o3_m1_attr_2", d, types, 1); /* attr a added to in base optional, declared/added in module , added to in other module optional */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m1_attr_4", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "g_m1_type_7"; test_attr_types(base, "g_m1_attr_4", NULL, types, 1); /* module 2 */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2"); types[0] = "o2_m2_type_1"; test_attr_types(base, "g_m1_attr_4", d, types, 1); /* base add */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b"); types[0] = "o5_b_type_1"; test_attr_types(base, "g_m1_attr_4", d, types, 1); /* attr a added to in base optional, declared/added in module optional, added to in other module optional */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o4_m1"); decls[0] = d->decl_id; test_sym_presence(base, "o4_m1_attr_1", SYM_TYPES, SCOPE_DECL, decls, 1); types[0] = "o4_m1_type_1"; test_attr_types(base, "o4_m1_attr_1", d, types, 1); /* module 2 */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o2_m2"); types[0] = "o2_m2_type_2"; test_attr_types(base, "o4_m1_attr_1", d, types, 1); /* base add */ d = test_find_decl_by_sym(base, SYM_TYPES, "tag_o5_b"); types[0] = "o5_b_type_2"; test_attr_types(base, "o4_m1_attr_1", d, types, 1); /* tests for aliases */ decls[0] = (test_find_decl_by_sym(base, SYM_TYPES, "tag_g_m1"))->decl_id; test_sym_presence(base, "g_m_alias_1", SYM_TYPES, SCOPE_DECL, decls, 1); test_alias_datum(base, "g_m_alias_1", "g_b_type_3", 1, 0); } libsepol-2.2/tests/test-linker-types.h000066400000000000000000000020021223423440700200770ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_LINKER_TYPES_H__ #define __TEST_LINKER_TYPES_H__ extern void base_type_tests(policydb_t * base); extern void module_type_tests(policydb_t * base); #endif libsepol-2.2/tests/test-linker.c000066400000000000000000000073331223423440700167440ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ /* This is where the linker tests should go, including: * - check role, type, bool, user, attr mapping * - check for properly enabled optional * - check for properly disabled optional * - check for non-optional disabled blocks * - properly add symbols declared in optionals */ #include "test-linker.h" #include "parse_util.h" #include "helpers.h" #include "test-common.h" #include "test-linker-roles.h" #include "test-linker-types.h" #include "test-linker-cond-map.h" #include #include #include #include #include #include #define NUM_MODS 2 #define NUM_POLICIES NUM_MODS+1 #define BASEMOD NUM_MODS const char *policies[NUM_POLICIES] = { "module1.conf", "module2.conf", "small-base.conf", }; static policydb_t basenomods; static policydb_t linkedbase; static policydb_t *modules[NUM_MODS]; extern int mls; int linker_test_init(void) { int i; if (test_load_policy(&linkedbase, POLICY_BASE, mls, "test-linker", policies[BASEMOD])) return -1; if (test_load_policy(&basenomods, POLICY_BASE, mls, "test-linker", policies[BASEMOD])) return -1; for (i = 0; i < NUM_MODS; i++) { modules[i] = calloc(1, sizeof(*modules[i])); if (!modules[i]) { fprintf(stderr, "out of memory!\n"); return -1; } if (test_load_policy(modules[i], POLICY_MOD, mls, "test-linker", policies[i])) return -1; } if (link_modules(NULL, &linkedbase, modules, NUM_MODS, 0)) { fprintf(stderr, "link modules failed\n"); return -1; } if (link_modules(NULL, &basenomods, NULL, 0, 0)) { fprintf(stderr, "link modules failed\n"); return -1; } return 0; } int linker_test_cleanup(void) { int i; policydb_destroy(&basenomods); policydb_destroy(&linkedbase); for (i = 0; i < NUM_MODS; i++) { policydb_destroy(modules[i]); free(modules[i]); } return 0; } static void test_linker_indexes(void) { test_policydb_indexes(&linkedbase); } static void test_linker_roles(void) { base_role_tests(&basenomods); base_role_tests(&linkedbase); module_role_tests(&linkedbase); } static void test_linker_types(void) { base_type_tests(&basenomods); base_type_tests(&linkedbase); module_type_tests(&linkedbase); } static void test_linker_cond(void) { base_cond_tests(&basenomods); base_cond_tests(&linkedbase); module_cond_tests(&linkedbase); } int linker_add_tests(CU_pSuite suite) { if (NULL == CU_add_test(suite, "linker_indexes", test_linker_indexes)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "linker_types", test_linker_types)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "linker_roles", test_linker_roles)) { CU_cleanup_registry(); return CU_get_error(); } if (NULL == CU_add_test(suite, "linker_cond", test_linker_cond)) { CU_cleanup_registry(); return CU_get_error(); } return 0; } libsepol-2.2/tests/test-linker.h000066400000000000000000000020201223423440700167350ustar00rootroot00000000000000/* * Author: Joshua Brindle * * 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 */ #ifndef __TEST_LINKER_H__ #define __TEST_LINKER_H__ #include int linker_test_init(void); int linker_test_cleanup(void); int linker_add_tests(CU_pSuite suite); #endif libsepol-2.2/utils/000077500000000000000000000000001223423440700143275ustar00rootroot00000000000000libsepol-2.2/utils/Makefile000066400000000000000000000006041223423440700157670ustar00rootroot00000000000000# Installation directories. PREFIX ?= $(DESTDIR)/usr BINDIR ?= $(PREFIX)/bin CFLAGS ?= -Wall -Werror override CFLAGS += -I../include LDLIBS += -L../src -lsepol TARGETS=$(patsubst %.c,%,$(wildcard *.c)) all: $(TARGETS) install: all -mkdir -p $(BINDIR) install -m 755 $(TARGETS) $(BINDIR) clean: -rm -f $(TARGETS) *.o indent: ../../scripts/Lindent $(wildcard *.[ch]) relabel: libsepol-2.2/utils/chkcon.c000066400000000000000000000014421223423440700157410ustar00rootroot00000000000000#include #include #include #include #include #include #include void usage(char*) __attribute__((noreturn)); void usage(char *progname) { printf("usage: %s policy context\n", progname); exit(1); } int main(int argc, char **argv) { FILE *fp; if (argc != 3) usage(argv[0]); fp = fopen(argv[1], "r"); if (!fp) { fprintf(stderr, "Can't open '%s': %s\n", argv[1], strerror(errno)); exit(1); } if (sepol_set_policydb_from_file(fp) < 0) { fprintf(stderr, "Error while processing %s: %s\n", argv[1], strerror(errno)); exit(1); } fclose(fp); if (sepol_check_context(argv[2]) < 0) { fprintf(stderr, "%s is not valid\n", argv[2]); exit(1); } printf("%s is valid\n", argv[2]); exit(0); }