diff options
author | SE Android <seandroid@taiga.selinuxproject.org> | 2012-01-24 05:26:38 -0800 |
---|---|---|
committer | SE Android <seandroid@taiga.selinuxproject.org> | 2012-01-24 05:26:38 -0800 |
commit | 255e72915d4cbddceb435e13d81601755714e9f3 (patch) | |
tree | d9e146f714ac6197865554529bcd1e3d10cbaec2 | |
download | libsepol-255e72915d4cbddceb435e13d81601755714e9f3.tar.gz |
Import libsepol 2.1.0 (Release 2011-07-27).
174 files changed, 39829 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a74c98b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +utils/chkcon @@ -0,0 +1,504 @@ + 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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..8d9c9c0 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,750 @@ +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 "<<none>>". + +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 <sepol/policydb/*.h>. + These headers should only be used by users of the static libsepol. + Created new <sepol/policydb.h> with new public types and interfaces + for shared libsepol. + Created new <sepol/module.h> 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d526965 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +all: + $(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 + @@ -0,0 +1 @@ +2.1.0 diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 0000000..0cd00ab --- /dev/null +++ b/include/Makefile @@ -0,0 +1,12 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +INCDIR ?= $(PREFIX)/include/sepol + +install: + 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) diff --git a/include/sepol/boolean_record.h b/include/sepol/boolean_record.h new file mode 100644 index 0000000..54ca021 --- /dev/null +++ b/include/sepol/boolean_record.h @@ -0,0 +1,51 @@ +#ifndef _SEPOL_BOOLEAN_RECORD_H_ +#define _SEPOL_BOOLEAN_RECORD_H_ + +#include <stddef.h> +#include <sepol/handle.h> + +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 diff --git a/include/sepol/booleans.h b/include/sepol/booleans.h new file mode 100644 index 0000000..95ee7de --- /dev/null +++ b/include/sepol/booleans.h @@ -0,0 +1,59 @@ +#ifndef _SEPOL_BOOLEANS_H_ +#define _SEPOL_BOOLEANS_H_ + +#include <stddef.h> +#include <sepol/policydb.h> +#include <sepol/boolean_record.h> +#include <sepol/handle.h> + +/*--------------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 diff --git a/include/sepol/context.h b/include/sepol/context.h new file mode 100644 index 0000000..c1eadca --- /dev/null +++ b/include/sepol/context.h @@ -0,0 +1,25 @@ +#ifndef _SEPOL_CONTEXT_H_ +#define _SEPOL_CONTEXT_H_ + +#include <sepol/context_record.h> +#include <sepol/policydb.h> +#include <sepol/handle.h> + +/* -- 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 diff --git a/include/sepol/context_record.h b/include/sepol/context_record.h new file mode 100644 index 0000000..c305480 --- /dev/null +++ b/include/sepol/context_record.h @@ -0,0 +1,53 @@ +#ifndef _SEPOL_CONTEXT_RECORD_H_ +#define _SEPOL_CONTEXT_RECORD_H_ + +#include <sepol/handle.h> + +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 diff --git a/include/sepol/debug.h b/include/sepol/debug.h new file mode 100644 index 0000000..3370845 --- /dev/null +++ b/include/sepol/debug.h @@ -0,0 +1,34 @@ +#ifndef _SEPOL_DEBUG_H_ +#define _SEPOL_DEBUG_H_ + +#include <sepol/handle.h> + +/* 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 diff --git a/include/sepol/errcodes.h b/include/sepol/errcodes.h new file mode 100644 index 0000000..c6f3a8b --- /dev/null +++ b/include/sepol/errcodes.h @@ -0,0 +1,25 @@ +/* Author: Karl MacMillan <kmacmillan@mentalrootkit.com> */ + +#ifndef __sepol_errno_h__ +#define __sepol_errno_h__ + +#include <errno.h> + +#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 diff --git a/include/sepol/handle.h b/include/sepol/handle.h new file mode 100644 index 0000000..19be326 --- /dev/null +++ b/include/sepol/handle.h @@ -0,0 +1,27 @@ +#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 *); + +#endif diff --git a/include/sepol/iface_record.h b/include/sepol/iface_record.h new file mode 100644 index 0000000..a72678c --- /dev/null +++ b/include/sepol/iface_record.h @@ -0,0 +1,59 @@ +#ifndef _SEPOL_IFACE_RECORD_H_ +#define _SEPOL_IFACE_RECORD_H_ + +#include <sepol/handle.h> +#include <sepol/context_record.h> + +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 diff --git a/include/sepol/interfaces.h b/include/sepol/interfaces.h new file mode 100644 index 0000000..9849e13 --- /dev/null +++ b/include/sepol/interfaces.h @@ -0,0 +1,43 @@ +#ifndef __SEPOL_INTERFACES_H_ +#define __SEPOL_INTERFACES_H_ + +#include <sepol/policydb.h> +#include <sepol/iface_record.h> +#include <sepol/handle.h> + +/* 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 diff --git a/include/sepol/module.h b/include/sepol/module.h new file mode 100644 index 0000000..35f5cb7 --- /dev/null +++ b/include/sepol/module.h @@ -0,0 +1,82 @@ +#ifndef _SEPOL_MODULE_H_ +#define _SEPOL_MODULE_H_ + +#include <stddef.h> +#include <stdio.h> +#include <stdint.h> + +#include <sepol/handle.h> +#include <sepol/policydb.h> + +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 diff --git a/include/sepol/node_record.h b/include/sepol/node_record.h new file mode 100644 index 0000000..9f61ac7 --- /dev/null +++ b/include/sepol/node_record.h @@ -0,0 +1,92 @@ +#ifndef _SEPOL_NODE_RECORD_H_ +#define _SEPOL_NODE_RECORD_H_ + +#include <stddef.h> +#include <sepol/context_record.h> +#include <sepol/handle.h> + +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 diff --git a/include/sepol/nodes.h b/include/sepol/nodes.h new file mode 100644 index 0000000..1e0ac4f --- /dev/null +++ b/include/sepol/nodes.h @@ -0,0 +1,40 @@ +#ifndef _SEPOL_NODES_H_ +#define _SEPOL_NODES_H_ + +#include <sepol/handle.h> +#include <sepol/policydb.h> +#include <sepol/node_record.h> + +/* 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 diff --git a/include/sepol/policydb.h b/include/sepol/policydb.h new file mode 100644 index 0000000..43e23b3 --- /dev/null +++ b/include/sepol/policydb.h @@ -0,0 +1,138 @@ +#ifndef _SEPOL_POLICYDB_H_ +#define _SEPOL_POLICYDB_H_ + +#include <stddef.h> +#include <stdio.h> + +#include <sepol/handle.h> + +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 diff --git a/include/sepol/policydb/avrule_block.h b/include/sepol/policydb/avrule_block.h new file mode 100644 index 0000000..dc926e5 --- /dev/null +++ b/include/sepol/policydb/avrule_block.h @@ -0,0 +1,37 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * + * 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 <sepol/policydb/policydb.h> + +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 diff --git a/include/sepol/policydb/avtab.h b/include/sepol/policydb/avtab.h new file mode 100644 index 0000000..6955ecf --- /dev/null +++ b/include/sepol/policydb/avtab.h @@ -0,0 +1,127 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> + * Tuned number of hash slots for avtab to reduce memory usage + */ + +/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <sys/types.h> +#include <stdint.h> + +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 */ diff --git a/include/sepol/policydb/conditional.h b/include/sepol/policydb/conditional.h new file mode 100644 index 0000000..a8ed694 --- /dev/null +++ b/include/sepol/policydb/conditional.h @@ -0,0 +1,134 @@ +/* Authors: Karl MacMillan <kmacmillan@tresys.com> + * Frank Mayer <mayerf@tresys.com> + * + * 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 <sepol/policydb/flask_types.h> +#include <sepol/policydb/avtab.h> +#include <sepol/policydb/symtab.h> +#include <sepol/policydb/policydb.h> + +#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 using 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; +} 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_ */ diff --git a/include/sepol/policydb/constraint.h b/include/sepol/policydb/constraint.h new file mode 100644 index 0000000..4c16ab0 --- /dev/null +++ b/include/sepol/policydb/constraint.h @@ -0,0 +1,77 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/ebitmap.h> +#include <sepol/policydb/flask_types.h> + +#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 */ diff --git a/include/sepol/policydb/context.h b/include/sepol/policydb/context.h new file mode 100644 index 0000000..8d74a25 --- /dev/null +++ b/include/sepol/policydb/context.h @@ -0,0 +1,97 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <stddef.h> +#include <sepol/policydb/ebitmap.h> +#include <sepol/policydb/mls_types.h> + +/* + * 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 diff --git a/include/sepol/policydb/ebitmap.h b/include/sepol/policydb/ebitmap.h new file mode 100644 index 0000000..410c15c --- /dev/null +++ b/include/sepol/policydb/ebitmap.h @@ -0,0 +1,88 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <stdint.h> +#include <string.h> + +#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_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 */ diff --git a/include/sepol/policydb/expand.h b/include/sepol/policydb/expand.h new file mode 100644 index 0000000..31e25ec --- /dev/null +++ b/include/sepol/policydb/expand.h @@ -0,0 +1,79 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <stddef.h> +#include <sepol/handle.h> +#include <sepol/policydb/conditional.h> + +/* + * 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 diff --git a/include/sepol/policydb/flask.h b/include/sepol/policydb/flask.h new file mode 100644 index 0000000..3134284 --- /dev/null +++ b/include/sepol/policydb/flask.h @@ -0,0 +1,94 @@ +/* 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 diff --git a/include/sepol/policydb/flask_types.h b/include/sepol/policydb/flask_types.h new file mode 100644 index 0000000..575c6f2 --- /dev/null +++ b/include/sepol/policydb/flask_types.h @@ -0,0 +1,62 @@ + +/* -*- linux-c -*- */ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +#ifndef _SEPOL_POLICYDB_FLASK_TYPES_H_ +#define _SEPOL_POLICYDB_FLASK_TYPES_H_ + +/* + * The basic Flask types and constants. + */ + +#include <sys/types.h> +#include <stdint.h> + +/* + * 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 diff --git a/include/sepol/policydb/hashtab.h b/include/sepol/policydb/hashtab.h new file mode 100644 index 0000000..1081ff6 --- /dev/null +++ b/include/sepol/policydb/hashtab.h @@ -0,0 +1,137 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <sepol/errcodes.h> + +#include <stdint.h> +#include <stdio.h> + +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 diff --git a/include/sepol/policydb/hierarchy.h b/include/sepol/policydb/hierarchy.h new file mode 100644 index 0000000..de2dfc7 --- /dev/null +++ b/include/sepol/policydb/hierarchy.h @@ -0,0 +1,32 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <sepol/policydb/policydb.h> + +extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p); + +#endif diff --git a/include/sepol/policydb/link.h b/include/sepol/policydb/link.h new file mode 100644 index 0000000..fca9114 --- /dev/null +++ b/include/sepol/policydb/link.h @@ -0,0 +1,20 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@mentalrootkit.com> + */ + +#ifndef _SEPOL_POLICYDB_LINK_H +#define _SEPOL_POLICYDB_LINK_H + +#include <sepol/handle.h> +#include <sepol/errcodes.h> +#include <sepol/policydb/policydb.h> + + +#include <stddef.h> + +extern int link_modules(sepol_handle_t * handle, + policydb_t * b, policydb_t ** mods, int len, + int verbose); + +#endif diff --git a/include/sepol/policydb/mls_types.h b/include/sepol/policydb/mls_types.h new file mode 100644 index 0000000..e491209 --- /dev/null +++ b/include/sepol/policydb/mls_types.h @@ -0,0 +1,153 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * 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 <stdint.h> +#include <stdlib.h> +#include <sepol/policydb/ebitmap.h> +#include <sepol/policydb/flask_types.h> + +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 diff --git a/include/sepol/policydb/module.h b/include/sepol/policydb/module.h new file mode 100644 index 0000000..10403c8 --- /dev/null +++ b/include/sepol/policydb/module.h @@ -0,0 +1,48 @@ +/* Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <stdlib.h> +#include <stddef.h> + +#include <sepol/module.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> + +#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 diff --git a/include/sepol/policydb/polcaps.h b/include/sepol/policydb/polcaps.h new file mode 100644 index 0000000..40c0a48 --- /dev/null +++ b/include/sepol/policydb/polcaps.h @@ -0,0 +1,18 @@ +#ifndef _SEPOL_POLICYDB_POLCAPS_H_ +#define _SEPOL_POLICYDB_POLCAPS_H_ + +/* Policy capabilities */ +enum { + POLICYDB_CAPABILITY_NETPEER, + POLICYDB_CAPABILITY_OPENPERM, + __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_ */ diff --git a/include/sepol/policydb/policydb.h b/include/sepol/policydb/policydb.h new file mode 100644 index 0000000..5320bc8 --- /dev/null +++ b/include/sepol/policydb/policydb.h @@ -0,0 +1,724 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated: Joshua Brindle <jbrindle@tresys.com> + * Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Module support + * + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com> + * + * 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 <stdio.h> +#include <stddef.h> + +#include <sepol/policydb.h> + +#include <sepol/policydb/flask_types.h> +#include <sepol/policydb/symtab.h> +#include <sepol/policydb/avtab.h> +#include <sepol/policydb/context.h> +#include <sepol/policydb/constraint.h> +#include <sepol/policydb/sidtab.h> + +#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 */ +} 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; +} 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 + +/* Range of policy versions we understand*/ +#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS + +/* 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_MIN MOD_POLICYDB_VERSION_BASE +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_ROLEATTRIB + +#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 */ diff --git a/include/sepol/policydb/services.h b/include/sepol/policydb/services.h new file mode 100644 index 0000000..aef0c7b --- /dev/null +++ b/include/sepol/policydb/services.h @@ -0,0 +1,184 @@ + +/* -*- linux-c -*- */ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ + +#ifndef _SEPOL_POLICYDB_SERVICES_H_ +#define _SEPOL_POLICYDB_SERVICES_H_ + +/* + * Security server interface. + */ + +#include <sepol/policydb/flask_types.h> +#include <sepol/policydb/policydb.h> +#include <stddef.h> + +/* 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); + +/* + * 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 diff --git a/include/sepol/policydb/sidtab.h b/include/sepol/policydb/sidtab.h new file mode 100644 index 0000000..33c7cb5 --- /dev/null +++ b/include/sepol/policydb/sidtab.h @@ -0,0 +1,72 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <sepol/policydb/context.h> + +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 */ diff --git a/include/sepol/policydb/symtab.h b/include/sepol/policydb/symtab.h new file mode 100644 index 0000000..c8ad664 --- /dev/null +++ b/include/sepol/policydb/symtab.h @@ -0,0 +1,38 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* 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 <sepol/policydb/hashtab.h> + +/* 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); + +#endif /* _SYMTAB_H_ */ + +/* FLASK */ diff --git a/include/sepol/policydb/util.h b/include/sepol/policydb/util.h new file mode 100644 index 0000000..40bfaa6 --- /dev/null +++ b/include/sepol/policydb/util.h @@ -0,0 +1,31 @@ +/* Authors: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 diff --git a/include/sepol/port_record.h b/include/sepol/port_record.h new file mode 100644 index 0000000..b347e08 --- /dev/null +++ b/include/sepol/port_record.h @@ -0,0 +1,66 @@ +#ifndef _SEPOL_PORT_RECORD_H_ +#define _SEPOL_PORT_RECORD_H_ + +#include <sepol/context_record.h> +#include <sepol/handle.h> + +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 diff --git a/include/sepol/ports.h b/include/sepol/ports.h new file mode 100644 index 0000000..fb94117 --- /dev/null +++ b/include/sepol/ports.h @@ -0,0 +1,40 @@ +#ifndef _SEPOL_PORTS_H_ +#define _SEPOL_PORTS_H_ + +#include <sepol/handle.h> +#include <sepol/policydb.h> +#include <sepol/port_record.h> + +/* 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 diff --git a/include/sepol/roles.h b/include/sepol/roles.h new file mode 100644 index 0000000..113f9d2 --- /dev/null +++ b/include/sepol/roles.h @@ -0,0 +1,10 @@ +#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 diff --git a/include/sepol/sepol.h b/include/sepol/sepol.h new file mode 100644 index 0000000..c8900d3 --- /dev/null +++ b/include/sepol/sepol.h @@ -0,0 +1,28 @@ +#ifndef _SEPOL_H_ +#define _SEPOL_H_ + +#include <stddef.h> +#include <stdio.h> + +#include <sepol/user_record.h> +#include <sepol/context_record.h> +#include <sepol/iface_record.h> +#include <sepol/port_record.h> +#include <sepol/boolean_record.h> +#include <sepol/node_record.h> + +#include <sepol/booleans.h> +#include <sepol/interfaces.h> +#include <sepol/ports.h> +#include <sepol/nodes.h> +#include <sepol/users.h> +#include <sepol/handle.h> +#include <sepol/debug.h> +#include <sepol/policydb.h> +#include <sepol/module.h> +#include <sepol/context.h> + +/* Set internal policydb from a file for subsequent service calls. */ +extern int sepol_set_policydb_from_file(FILE * fp); + +#endif diff --git a/include/sepol/user_record.h b/include/sepol/user_record.h new file mode 100644 index 0000000..c86ad16 --- /dev/null +++ b/include/sepol/user_record.h @@ -0,0 +1,76 @@ +#ifndef _SEPOL_USER_RECORD_H_ +#define _SEPOL_USER_RECORD_H_ + +#include <stddef.h> +#include <sepol/handle.h> + +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 diff --git a/include/sepol/users.h b/include/sepol/users.h new file mode 100644 index 0000000..01b0775 --- /dev/null +++ b/include/sepol/users.h @@ -0,0 +1,57 @@ +#ifndef _SEPOL_USERS_H_ +#define _SEPOL_USERS_H_ + +#include <sepol/policydb.h> +#include <sepol/user_record.h> +#include <sepol/handle.h> +#include <stddef.h> + +/*---------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 diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 0000000..b96bc94 --- /dev/null +++ b/man/Makefile @@ -0,0 +1,10 @@ +# Installation directories. +MAN8DIR ?= $(DESTDIR)/usr/share/man/man8 +MAN3DIR ?= $(DESTDIR)/usr/share/man/man3 + +install: + mkdir -p $(MAN3DIR) + mkdir -p $(MAN8DIR) + install -m 644 man3/*.3 $(MAN3DIR) + install -m 644 man8/*.8 $(MAN8DIR) + diff --git a/man/man3/sepol_check_context.3 b/man/man3/sepol_check_context.3 new file mode 100644 index 0000000..a63cd56 --- /dev/null +++ b/man/man3/sepol_check_context.3 @@ -0,0 +1,25 @@ +.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 <sepol/sepol.h> +.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. diff --git a/man/man3/sepol_genbools.3 b/man/man3/sepol_genbools.3 new file mode 100644 index 0000000..0a30137 --- /dev/null +++ b/man/man3/sepol_genbools.3 @@ -0,0 +1,30 @@ +.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 <sepol/sepol.h> +.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. + diff --git a/man/man3/sepol_genusers.3 b/man/man3/sepol_genusers.3 new file mode 100644 index 0000000..05dff00 --- /dev/null +++ b/man/man3/sepol_genusers.3 @@ -0,0 +1,54 @@ +.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 <sepol/sepol.h> +.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. diff --git a/man/man8/chkcon.8 b/man/man8/chkcon.8 new file mode 100644 index 0000000..f8d75df --- /dev/null +++ b/man/man8/chkcon.8 @@ -0,0 +1,41 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org> +.\" +.\" 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 <srivasta@debian.org>. + diff --git a/man/man8/genpolbools.8 b/man/man8/genpolbools.8 new file mode 100644 index 0000000..afeaced --- /dev/null +++ b/man/man8/genpolbools.8 @@ -0,0 +1,16 @@ +.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. + + + + diff --git a/man/man8/genpolusers.8 b/man/man8/genpolusers.8 new file mode 100644 index 0000000..34d729a --- /dev/null +++ b/man/man8/genpolusers.8 @@ -0,0 +1,42 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.\" Copyright (c) 1997 Manoj Srivastava <srivasta@debian.org> +.\" +.\" 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 <srivasta@debian.org>. diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..73fdef8 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,56 @@ +# Installation directories. +PREFIX ?= $(DESTDIR)/usr +INCLUDEDIR ?= $(PREFIX)/include +LIBDIR ?= $(PREFIX)/lib +SHLIBDIR ?= $(DESTDIR)/lib +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 + 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]) + diff --git a/src/assertion.c b/src/assertion.c new file mode 100644 index 0000000..a6e0c04 --- /dev/null +++ b/src/assertion.c @@ -0,0 +1,151 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * + * Assertion checker for avtab entries, taken from + * checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov> + * + * 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 <sepol/policydb/avtab.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/util.h> + +#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; +} diff --git a/src/av_permissions.h b/src/av_permissions.h new file mode 100644 index 0000000..97278ed --- /dev/null +++ b/src/av_permissions.h @@ -0,0 +1,3 @@ +/* Used by security_compute_av. */ +#define PROCESS__TRANSITION 0x00000002UL +#define PROCESS__DYNTRANSITION 0x00800000UL diff --git a/src/avrule_block.c b/src/avrule_block.c new file mode 100644 index 0000000..16c89f3 --- /dev/null +++ b/src/avrule_block.c @@ -0,0 +1,202 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/avrule_block.h> + +#include <assert.h> +#include <stdlib.h> + +/* 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); + free(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; +} diff --git a/src/avtab.c b/src/avtab.c new file mode 100644 index 0000000..ea947cb --- /dev/null +++ b/src/avtab.c @@ -0,0 +1,531 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> + * Tuned number of hash slots for avtab to reduce memory usage + */ + +/* Updated: Frank Mayer <mayerf@tresys.com> + * and Karl MacMillan <kmacmillan@mentalrootkit.com> + * + * Added conditional policy language extensions + * + * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com> + * + * Code cleanup + * + * Updated: Karl MacMillan <kmacmillan@mentalrootkit.com> + * + * 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 <stdlib.h> +#include <sepol/policydb/avtab.h> +#include <sepol/policydb/policydb.h> +#include <sepol/errcodes.h> + +#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; +} diff --git a/src/boolean_internal.h b/src/boolean_internal.h new file mode 100644 index 0000000..aad7ade --- /dev/null +++ b/src/boolean_internal.h @@ -0,0 +1,16 @@ +#ifndef _SEPOL_BOOLEAN_INTERNAL_H_ +#define _SEPOL_BOOLEAN_INTERNAL_H_ + +#include <sepol/boolean_record.h> +#include <sepol/booleans.h> +#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 diff --git a/src/boolean_record.c b/src/boolean_record.c new file mode 100644 index 0000000..8b64413 --- /dev/null +++ b/src/boolean_record.c @@ -0,0 +1,180 @@ +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#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) diff --git a/src/booleans.c b/src/booleans.c new file mode 100644 index 0000000..03f8c98 --- /dev/null +++ b/src/booleans.c @@ -0,0 +1,216 @@ +#include <string.h> +#include <stdlib.h> + +#include "handle.h" +#include "private.h" +#include "debug.h" + +#include <sepol/booleans.h> +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#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; +} diff --git a/src/conditional.c b/src/conditional.c new file mode 100644 index 0000000..1482387 --- /dev/null +++ b/src/conditional.c @@ -0,0 +1,905 @@ +/* Authors: Karl MacMillan <kmacmillan@tresys.com> + * Frank Mayer <mayerf@tresys.com> + * David Caplan <dac@tresys.com> + * + * 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 <stdlib.h> + +#include <sepol/policydb/flask_types.h> +#include <sepol/policydb/conditional.h> + +#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; + } + + 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 + __attribute__ ((unused)), 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 (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; + } + + 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; + +} diff --git a/src/constraint.c b/src/constraint.c new file mode 100644 index 0000000..7154019 --- /dev/null +++ b/src/constraint.c @@ -0,0 +1,47 @@ +/* Authors: Jason Tang <jtang@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/constraint.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/flask_types.h> + +#include <assert.h> +#include <stdlib.h> + +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); + } +} diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..84dad34 --- /dev/null +++ b/src/context.c @@ -0,0 +1,338 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#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; +} diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..d25ca8a --- /dev/null +++ b/src/context.h @@ -0,0 +1,37 @@ +#ifndef _SEPOL_INTERNAL_CONTEXT_H_ +#define _SEPOL_INTERNAL_CONTEXT_H_ + +#include <stddef.h> +#include "context_internal.h" +#include <sepol/policydb/context.h> +#include <sepol/policydb/policydb.h> +#include <sepol/handle.h> + +/* 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 diff --git a/src/context_internal.h b/src/context_internal.h new file mode 100644 index 0000000..7987c1c --- /dev/null +++ b/src/context_internal.h @@ -0,0 +1,19 @@ +#ifndef _SEPOL_CONTEXT_INTERNAL_H_ +#define _SEPOL_CONTEXT_INTERNAL_H_ + +#include <sepol/context_record.h> +#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 diff --git a/src/context_record.c b/src/context_record.c new file mode 100644 index 0000000..ac2884a --- /dev/null +++ b/src/context_record.c @@ -0,0 +1,324 @@ +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#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, "<<none>>")) { + *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; +} diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..51918fd --- /dev/null +++ b/src/debug.c @@ -0,0 +1,89 @@ +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#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; +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..56b397b --- /dev/null +++ b/src/debug.h @@ -0,0 +1,74 @@ +/* + * 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 <stdio.h> +#include <sepol/debug.h> +#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 diff --git a/src/dso.h b/src/dso.h new file mode 100644 index 0000000..5c69aae --- /dev/null +++ b/src/dso.h @@ -0,0 +1,23 @@ +#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 diff --git a/src/ebitmap.c b/src/ebitmap.c new file mode 100644 index 0000000..cc6a915 --- /dev/null +++ b/src/ebitmap.c @@ -0,0 +1,368 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* FLASK */ + +/* + * Implementation of the extensible bitmap type. + */ + +#include <stdlib.h> + +#include <sepol/policydb/ebitmap.h> +#include <sepol/policydb/policydb.h> + +#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_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 */ diff --git a/src/expand.c b/src/expand.c new file mode 100644 index 0000000..b42acbe --- /dev/null +++ b/src/expand.c @@ -0,0 +1,3179 @@ +/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> + * Jason Tang <jtang@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/avrule_block.h> + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#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; + +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(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) { + /* 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_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++; + + 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 (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!"); + 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]); + 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!"); + 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 (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; + + 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) { + if ((cur_trans->role == + i + 1) && + (cur_trans->type == + j + 1) && + (cur_trans->tclass == + k + 1)) { + if (cur_trans-> + new_role == + cur->new_role) { + break; + } else { + ERR(state->handle, + "Conflicting role trans rule %s %s : %s %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[cur->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, *tail, *cur_trans; + filename_trans_rule_t *cur_rule; + ebitmap_t stypes, ttypes; + ebitmap_node_t *snode, *tnode; + + /* start at the end of the list */ + tail = state->out->filename_trans; + while (tail && tail->next) + tail = tail->next; + + cur_rule = rules; + while (cur_rule) { + 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; + } + + 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 = state->out->filename_trans; + while (cur_trans) { + if ((cur_trans->stype == i + 1) && + (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 == cur_rule->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[state->typemap[cur_rule->otype - 1] - 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)); + if (tail) + tail->next = new_trans; + else + state->out->filename_trans = new_trans; + tail = 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 = state->typemap[cur_rule->otype - 1]; + } + } + + 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) { + if ((retval = + expand_avrule_helper(handle, + source_rule-> + specified, cond, i, i, + source_rule->perms, + dest_avtab, + enabled)) != + EXPAND_RULE_SUCCESS) { + return retval; + } + } else { + if ((retval = + expand_terule_helper(handle, p, + typemap, + source_rule-> + specified, cond, + other, i, i, + source_rule->perms, + dest_avtab, + enabled)) != + 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) { + if ((retval = + expand_avrule_helper(handle, + source_rule-> + specified, cond, i, j, + source_rule->perms, + dest_avtab, + enabled)) != + EXPAND_RULE_SUCCESS) { + return retval; + } + } else { + if ((retval = + expand_terule_helper(handle, p, + typemap, + source_rule-> + specified, cond, + other, i, j, + source_rule->perms, + dest_avtab, + enabled)) != + 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 (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)) { + 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; + if (context_copy(&n->context[0], &c->context[0], + state)) { + ERR(state->handle, "Out of memory!"); + return -1; + } + switch (i) { + case OCON_XEN_ISID: + 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; + } + } + } + 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; + if (context_copy(&n->context[0], &c->context[0], state)) { + ERR(state->handle, "Out of memory!"); + return -1; + } + switch (i) { + case OCON_ISID: + 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; + } + } + } + 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) { + ERR(state->handle, "Out of memory!"); + return -1; + } + + 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!"); + 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; + } + if (!end) { + state->out->genfs = newgenfs; + } else { + end->next = newgenfs; + } + end = newgenfs; + } + 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); +} + +/* 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; + + 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; + if (hashtab_map + (decl->p_roles.table, role_fix_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); + evaluate_conds(state.out); + + /* 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 && ttype) { + /* Both are individual types, no expansion required. */ + return expand_avtab_insert(expa, k, d); + } + + if (stype) { + /* 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) { + /* 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 && ttype) { + /* Both are individual types, no expansion required. */ + return expand_cond_insert(newl, expa, k, d); + } + + if (stype) { + /* 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) { + /* 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; +} diff --git a/src/genbools.c b/src/genbools.c new file mode 100644 index 0000000..e353ef3 --- /dev/null +++ b/src/genbools.c @@ -0,0 +1,252 @@ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> + +#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; + 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; + + while (getline(&buffer, &size, boolf) > 0) { + 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) { + while (getline(&buffer, &size, boolf) > 0) { + 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; +} diff --git a/src/genusers.c b/src/genusers.c new file mode 100644 index 0000000..44f94e9 --- /dev/null +++ b/src/genusers.c @@ -0,0 +1,318 @@ +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> + +#include <sepol/policydb/policydb.h> +#include <stdarg.h> + +#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; + __fsetlocking(fp, FSETLOCKING_BYCALLER); + + while ((nread = getline(&buffer, &len, fp)) > 0) { + 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); + + /* Adding a new user definition. */ + usrdatum = + (user_datum_t *) malloc(sizeof(user_datum_t)); + if (!id || !usrdatum) { + ERR(NULL, "out of memory"); + free(buffer); + fclose(fp); + return -1; + } + memset(usrdatum, 0, sizeof(user_datum_t)); + usrdatum->s.value = ++policydb->p_users.nprim; + ebitmap_init(&usrdatum->roles.roles); + if (hashtab_insert(policydb->p_users.table, + id, (hashtab_datum_t) usrdatum)) { + ERR(NULL, "out of memory"); + free(buffer); + 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 -- */ diff --git a/src/handle.c b/src/handle.c new file mode 100644 index 0000000..191ac57 --- /dev/null +++ b/src/handle.c @@ -0,0 +1,45 @@ +#include <stdlib.h> +#include <assert.h> +#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; + + return sh; +} + +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); +} diff --git a/src/handle.h b/src/handle.h new file mode 100644 index 0000000..254fbd8 --- /dev/null +++ b/src/handle.h @@ -0,0 +1,23 @@ +#ifndef _SEPOL_INTERNAL_HANDLE_H_ +#define _SEPOL_INTERNAL_HANDLE_H_ + +#include <sepol/handle.h> + +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; + +}; + +#endif diff --git a/src/hashtab.c b/src/hashtab.c new file mode 100644 index 0000000..c4be72c --- /dev/null +++ b/src/hashtab.c @@ -0,0 +1,313 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated : Karl MacMillan <kmacmillan@mentalrootkit.com> + * + * 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 <stdlib.h> +#include <string.h> +#include <sepol/policydb/hashtab.h> + +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); +} diff --git a/src/hierarchy.c b/src/hierarchy.c new file mode 100644 index 0000000..e2df5a4 --- /dev/null +++ b/src/hierarchy.c @@ -0,0 +1,501 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * Updates: KaiGai Kohei <kaigai@ak.jp.nec.com> + * 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 <string.h> +#include <stdlib.h> +#include <assert.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/hierarchy.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/util.h> + +#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); + + /* + * 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; +} diff --git a/src/iface_internal.h b/src/iface_internal.h new file mode 100644 index 0000000..5b78d9b --- /dev/null +++ b/src/iface_internal.h @@ -0,0 +1,18 @@ +#ifndef _SEPOL_IFACE_INTERNAL_H_ +#define _SEPOL_IFACE_INTERNAL_H_ + +#include <sepol/iface_record.h> +#include <sepol/interfaces.h> +#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 diff --git a/src/iface_record.c b/src/iface_record.c new file mode 100644 index 0000000..09adeb7 --- /dev/null +++ b/src/iface_record.c @@ -0,0 +1,233 @@ +#include <stdlib.h> +#include <string.h> + +#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) diff --git a/src/interfaces.c b/src/interfaces.c new file mode 100644 index 0000000..b82d0f3 --- /dev/null +++ b/src/interfaces.c @@ -0,0 +1,273 @@ +#include <stdlib.h> + +#include "debug.h" +#include "context.h" +#include "handle.h" + +#include <sepol/policydb/policydb.h> +#include <sepol/interfaces.h> +#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; +} diff --git a/src/libsepol.map b/src/libsepol.map new file mode 100644 index 0000000..719e5b7 --- /dev/null +++ b/src/libsepol.map @@ -0,0 +1,19 @@ +{ + global: + 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; + local: *; +}; diff --git a/src/libsepol.pc.in b/src/libsepol.pc.in new file mode 100644 index 0000000..e52f589 --- /dev/null +++ b/src/libsepol.pc.in @@ -0,0 +1,11 @@ +prefix=@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} diff --git a/src/link.c b/src/link.c new file mode 100644 index 0000000..421c47b --- /dev/null +++ b/src/link.c @@ -0,0 +1,2598 @@ +/* Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> + * Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/avrule_block.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/util.h> + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#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_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"); + 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"); + 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; + + 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; + + } + + /* 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; + + 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; + } + 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; + } + } + + 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; + } + 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; + } + } + + 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 { + 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"); + 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) { + 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; + 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; + + hashtab_map(cladatum->permissions.table, find_perm, + &fparg); + if (fparg.key == NULL && cladatum->comdatum != NULL) + hashtab_map(cladatum->comdatum->permissions. + table, find_perm, &fparg); + 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; + + 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; + 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; + 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; +} diff --git a/src/mls.c b/src/mls.c new file mode 100644 index 0000000..1e84bb7 --- /dev/null +++ b/src/mls.c @@ -0,0 +1,798 @@ +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/flask.h> +#include <sepol/policydb/context.h> + +#include <stdlib.h> + +#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; +} diff --git a/src/mls.h b/src/mls.h new file mode 100644 index 0000000..98da3d3 --- /dev/null +++ b/src/mls.h @@ -0,0 +1,67 @@ +/* Author: Stephen Smalley, <sds@epoch.ncsc.mil> + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * 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 <sepol/policydb/context.h> +#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 diff --git a/src/module.c b/src/module.c new file mode 100644 index 0000000..b5b807e --- /dev/null +++ b/src/module.c @@ -0,0 +1,985 @@ +/* Author: Karl MacMillan <kmacmillan@tresys.com> + * Jason Tang <jtang@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * 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 <sepol/policydb/link.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/module.h> +#include "debug.h" +#include "private.h" + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#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 size_t policy_file_length(struct policy_file *fp) +{ + long prev_offset, end_offset; + switch (fp->type) { + case PF_USE_STDIO: + prev_offset = ftell(fp->fp); + fseek(fp->fp, 0L, SEEK_END); + end_offset = ftell(fp->fp); + fseek(fp->fp, prev_offset, SEEK_SET); + return end_offset; + case PF_USE_MEMORY: + return fp->size; + default: + 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) +{ + *p = calloc(1, sizeof(sepol_module_package_t)); + if (!(*p)) + return -1; + return module_package_init(*p); +} + +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; + } + } + + off[nsec] = policy_file_length(file); + 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); +} diff --git a/src/module_internal.h b/src/module_internal.h new file mode 100644 index 0000000..cdd5ec6 --- /dev/null +++ b/src/module_internal.h @@ -0,0 +1,5 @@ +#include <sepol/module.h> +#include "dso.h" + +hidden_proto(sepol_module_package_create) + hidden_proto(sepol_module_package_free) diff --git a/src/node_internal.h b/src/node_internal.h new file mode 100644 index 0000000..802cda9 --- /dev/null +++ b/src/node_internal.h @@ -0,0 +1,26 @@ +#ifndef _SEPOL_NODE_INTERNAL_H_ +#define _SEPOL_NODE_INTERNAL_H_ + +#include <sepol/node_record.h> +#include <sepol/nodes.h> +#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 diff --git a/src/node_record.c b/src/node_record.c new file mode 100644 index 0000000..b1bd370 --- /dev/null +++ b/src/node_record.c @@ -0,0 +1,668 @@ +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> + +#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; + } + + memcpy(addr_bytes, in_addr.s6_addr32, 16); + 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)); + memcpy(&addr.s6_addr32[0], addr_bytes, 16); + + 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) diff --git a/src/nodes.c b/src/nodes.c new file mode 100644 index 0000000..ebf5f1d --- /dev/null +++ b/src/nodes.c @@ -0,0 +1,400 @@ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> + +#include "debug.h" +#include "context.h" +#include "handle.h" + +#include <sepol/policydb/policydb.h> +#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; +} diff --git a/src/polcaps.c b/src/polcaps.c new file mode 100644 index 0000000..71970b1 --- /dev/null +++ b/src/polcaps.c @@ -0,0 +1,33 @@ +/* + * Policy capability support functions + */ + +#include <string.h> +#include <sepol/policydb/polcaps.h> + +static const char *polcap_names[] = { + "network_peer_controls", /* POLICYDB_CAPABILITY_NETPEER */ + "open_perms", /* POLICYDB_CAPABILITY_OPENPERM */ + 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]; +} diff --git a/src/policydb.c b/src/policydb.c new file mode 100644 index 0000000..53d0fda --- /dev/null +++ b/src/policydb.c @@ -0,0 +1,3843 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com> + * 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 <assert.h> +#include <stdlib.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/avrule_block.h> +#include <sepol/policydb/util.h> +#include <sepol/policydb/flask.h> + +#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_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_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, + }, +}; + +#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; + 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; + } + 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++) { + 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++) { + 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; + 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 (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; + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + return -1; + len = le32_to_cpu(buf[0]); + + name = calloc(len, 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; + + 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 { + last_decl->next = curdecl; + } + last_decl = curdecl; + num_decls--; + } + + if (*block == NULL) { + *block = curblock; + } else { + 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; +} + diff --git a/src/policydb_convert.c b/src/policydb_convert.c new file mode 100644 index 0000000..32832bb --- /dev/null +++ b/src/policydb_convert.c @@ -0,0 +1,100 @@ +#include <stdlib.h> + +#include "private.h" +#include "debug.h" + +#include <sepol/policydb/policydb.h> + +/* 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)) { + 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; +} diff --git a/src/policydb_internal.h b/src/policydb_internal.h new file mode 100644 index 0000000..8a31506 --- /dev/null +++ b/src/policydb_internal.h @@ -0,0 +1,10 @@ +#ifndef _SEPOL_POLICYDB_INTERNAL_H_ +#define _SEPOL_POLICYDB_INTERNAL_H_ + +#include <sepol/policydb.h> +#include "dso.h" + +hidden_proto(sepol_policydb_create) + hidden_proto(sepol_policydb_free) +extern char *policydb_target_strings[]; +#endif diff --git a/src/policydb_public.c b/src/policydb_public.c new file mode 100644 index 0000000..f6ae793 --- /dev/null +++ b/src/policydb_public.c @@ -0,0 +1,193 @@ +#include <stdlib.h> + +#include "debug.h" +#include <sepol/policydb/policydb.h> +#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); +} diff --git a/src/port_internal.h b/src/port_internal.h new file mode 100644 index 0000000..ffb5f65 --- /dev/null +++ b/src/port_internal.h @@ -0,0 +1,20 @@ +#ifndef _SEPOL_PORT_INTERNAL_H_ +#define _SEPOL_PORT_INTERNAL_H_ + +#include <sepol/port_record.h> +#include <sepol/ports.h> +#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 diff --git a/src/port_record.c b/src/port_record.c new file mode 100644 index 0000000..6a33d93 --- /dev/null +++ b/src/port_record.c @@ -0,0 +1,288 @@ +#include <stdlib.h> +#include <string.h> + +#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) diff --git a/src/ports.c b/src/ports.c new file mode 100644 index 0000000..cbf2a0b --- /dev/null +++ b/src/ports.c @@ -0,0 +1,312 @@ +#include <netinet/in.h> +#include <stdlib.h> + +#include "debug.h" +#include "context.h" +#include "handle.h" + +#include <sepol/policydb/policydb.h> +#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; +} diff --git a/src/private.h b/src/private.h new file mode 100644 index 0000000..b2b247e --- /dev/null +++ b/src/private.h @@ -0,0 +1,49 @@ +/* Private definitions for libsepol. */ + +/* Endian conversion for reading and writing binary policies */ + +#include <sepol/policydb/policydb.h> + +#include <byteswap.h> +#include <endian.h> +#include <errno.h> +#include <dso.h> + +#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)) + +#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; diff --git a/src/roles.c b/src/roles.c new file mode 100644 index 0000000..419a3b2 --- /dev/null +++ b/src/roles.c @@ -0,0 +1,55 @@ +#include <stdlib.h> +#include <string.h> + +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/policydb.h> + +#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; +} diff --git a/src/services.c b/src/services.c new file mode 100644 index 0000000..9c2920c --- /dev/null +++ b/src/services.c @@ -0,0 +1,1469 @@ + +/* + * Author : Stephen Smalley, <sds@epoch.ncsc.mil> + */ +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer <mayerf@tresys.com> + * and Karl MacMillan <kmacmillan@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Red Hat, Inc. James Morris <jmorris@redhat.com> + * + * 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. + */ + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/sidtab.h> +#include <sepol/policydb/services.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/flask.h> + +#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; + +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)) { + 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; + +/* + * 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 should pass in NULL for xcontext. + */ +static int constraint_expr_eval(context_struct_t * scontext, + context_struct_t * tcontext, + context_struct_t * xcontext, + constraint_expr_t * cexpr) +{ + 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; + + for (e = cexpr; e; e = e->next) { + switch (e->expr_type) { + case CEXPR_NOT: + BUG_ON(sp < 0); + s[sp] = !s[sp]; + break; + case CEXPR_AND: + BUG_ON(sp < 1); + sp--; + s[sp] &= s[sp + 1]; + break; + case CEXPR_OR: + BUG_ON(sp < 1); + sp--; + s[sp] |= s[sp + 1]; + break; + case CEXPR_ATTR: + if (sp == (CEXPR_MAXDEPTH - 1)) + return 0; + switch (e->attr) { + case CEXPR_USER: + val1 = scontext->user; + val2 = tcontext->user; + break; + case CEXPR_TYPE: + val1 = scontext->type; + val2 = tcontext->type; + 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]; + switch (e->op) { + case CEXPR_DOM: + s[++sp] = + ebitmap_get_bit(&r1->dominates, + val2 - 1); + continue; + case CEXPR_DOMBY: + s[++sp] = + ebitmap_get_bit(&r2->dominates, + val1 - 1); + continue; + case CEXPR_INCOMP: + s[++sp] = + (!ebitmap_get_bit + (&r1->dominates, val2 - 1) + && !ebitmap_get_bit(&r2->dominates, + val1 - 1)); + continue; + default: + break; + } + break; + case CEXPR_L1L2: + l1 = &(scontext->range.level[0]); + l2 = &(tcontext->range.level[0]); + goto mls_ops; + case CEXPR_L1H2: + l1 = &(scontext->range.level[0]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; + case CEXPR_H1L2: + l1 = &(scontext->range.level[1]); + l2 = &(tcontext->range.level[0]); + goto mls_ops; + case CEXPR_H1H2: + l1 = &(scontext->range.level[1]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; + case CEXPR_L1H1: + l1 = &(scontext->range.level[0]); + l2 = &(scontext->range.level[1]); + goto mls_ops; + case CEXPR_L2H2: + l1 = &(tcontext->range.level[0]); + l2 = &(tcontext->range.level[1]); + goto mls_ops; + mls_ops: + switch (e->op) { + case CEXPR_EQ: + s[++sp] = mls_level_eq(l1, l2); + continue; + case CEXPR_NEQ: + s[++sp] = !mls_level_eq(l1, l2); + continue; + case CEXPR_DOM: + s[++sp] = mls_level_dom(l1, l2); + continue; + case CEXPR_DOMBY: + s[++sp] = mls_level_dom(l2, l1); + continue; + case CEXPR_INCOMP: + s[++sp] = mls_level_incomp(l2, l1); + continue; + default: + BUG(); + return 0; + } + break; + default: + BUG(); + return 0; + } + + switch (e->op) { + case CEXPR_EQ: + s[++sp] = (val1 == val2); + break; + case CEXPR_NEQ: + s[++sp] = (val1 != val2); + break; + default: + BUG(); + return 0; + } + break; + case CEXPR_NAMES: + if (sp == (CEXPR_MAXDEPTH - 1)) + return 0; + c = scontext; + if (e->attr & CEXPR_TARGET) + c = tcontext; + else if (e->attr & CEXPR_XTARGET) { + c = xcontext; + if (!c) { + BUG(); + return 0; + } + } + if (e->attr & CEXPR_USER) + val1 = c->user; + else if (e->attr & CEXPR_ROLE) + val1 = c->role; + else if (e->attr & CEXPR_TYPE) + val1 = c->type; + else { + BUG(); + return 0; + } + + switch (e->op) { + case CEXPR_EQ: + s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); + break; + case CEXPR_NEQ: + s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); + break; + default: + BUG(); + return 0; + } + break; + default: + BUG(); + return 0; + } + } + + BUG_ON(sp != 0); + return s[0]; +} + +/* + * 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) +{ + 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(scontext, tcontext, NULL, + constraint->expr)) { + 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(ocontext, ncontext, tcontext, + constraint->expr)) { + 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); + 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); +} + +/* + * 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)) { + 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); + 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 */ diff --git a/src/sidtab.c b/src/sidtab.c new file mode 100644 index 0000000..5bd7999 --- /dev/null +++ b/src/sidtab.c @@ -0,0 +1,328 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* FLASK */ + +/* + * Implementation of the SID table type. + */ + +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> + +#include <sepol/policydb/sidtab.h> + +#include <sepol/policydb/flask.h> + +#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 */ diff --git a/src/symtab.c b/src/symtab.c new file mode 100644 index 0000000..b3a7aa8 --- /dev/null +++ b/src/symtab.c @@ -0,0 +1,49 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* FLASK */ + +/* + * Implementation of the symbol table type. + */ + +#include <string.h> +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/symtab.h> + +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; +} + +/* FLASK */ diff --git a/src/user_internal.h b/src/user_internal.h new file mode 100644 index 0000000..7523b7d --- /dev/null +++ b/src/user_internal.h @@ -0,0 +1,20 @@ +#ifndef _SEPOL_USER_INTERNAL_H_ +#define _SEPOL_USER_INTERNAL_H_ + +#include <sepol/user_record.h> +#include <sepol/users.h> +#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 diff --git a/src/user_record.c b/src/user_record.c new file mode 100644 index 0000000..c59c54b --- /dev/null +++ b/src/user_record.c @@ -0,0 +1,379 @@ +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#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) diff --git a/src/users.c b/src/users.c new file mode 100644 index 0000000..693210d --- /dev/null +++ b/src/users.c @@ -0,0 +1,383 @@ +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#include "private.h" +#include "debug.h" +#include "handle.h" + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/hashtab.h> +#include <sepol/policydb/expand.h> +#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; +} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..a824e61 --- /dev/null +++ b/src/util.c @@ -0,0 +1,116 @@ +/* Authors: Joshua Brindle <jbrindle@tresys.com> + * Jason Tang <jtang@tresys.com> + * + * 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include <sepol/policydb/flask_types.h> +#include <sepol/policydb/policydb.h> + +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; +} diff --git a/src/write.c b/src/write.c new file mode 100644 index 0000000..290e036 --- /dev/null +++ b/src/write.c @@ -0,0 +1,2009 @@ + +/* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ + +/* + * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * + * Support for enhanced MLS infrastructure. + * + * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> + * + * Added conditional policy language extensions + * + * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org> + * + * 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 <assert.h> +#include <stdlib.h> + +#include <sepol/policydb/ebitmap.h> +#include <sepol/policydb/avtab.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/flask.h> + +#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; + + 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; + 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; + } + + 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)) { + 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; + } + + 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; + + 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; + + 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... */ + if ((dyn_buf = malloc(items * sizeof(*dyn_buf))) == NULL) { + return POLICYDB_ERROR; + } + buf = dyn_buf; + } else { + buf = static_buf; + } + buf[0] = cpu_to_le32(key_len); + if (put_entry(buf, sizeof(*buf), 1, fp) != 1 || + put_entry(key, 1, key_len, fp) != key_len) { + return POLICYDB_ERROR; + } + 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]); + } + if (put_entry(buf, sizeof(*buf), items, fp) != items) { + free(dyn_buf); + return POLICYDB_ERROR; + } + free(dyn_buf); + return POLICYDB_SUCCESS; +} + +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; +} + +/* + * 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] = cpu_to_le32(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]); + } + 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; +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..dd7bd33 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,54 @@ +M4 ?= 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 diff --git a/tests/debug.c b/tests/debug.c new file mode 100644 index 0000000..90aa6e0 --- /dev/null +++ b/tests/debug.c @@ -0,0 +1,69 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <stdlib.h> + +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; + } + } +} diff --git a/tests/debug.h b/tests/debug.h new file mode 100644 index 0000000..c25ebd4 --- /dev/null +++ b/tests/debug.h @@ -0,0 +1,27 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> + +extern void print_ebitmap(ebitmap_t * bitmap, FILE * fp); +extern void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp); diff --git a/tests/helpers.c b/tests/helpers.c new file mode 100644 index 0000000..542e467 --- /dev/null +++ b/tests/helpers.c @@ -0,0 +1,81 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Chad Sellers <csellers@tresys.com> + * + * 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 <sepol/policydb/expand.h> +#include <sepol/policydb/avrule_block.h> + +#include <CUnit/Basic.h> + +#include <stdlib.h> +#include <limits.h> + +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]; +} diff --git a/tests/helpers.h b/tests/helpers.h new file mode 100644 index 0000000..418ee95 --- /dev/null +++ b/tests/helpers.h @@ -0,0 +1,59 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Chad Sellers <csellers@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/conditional.h> + +/* 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 diff --git a/tests/libsepol-tests.c b/tests/libsepol-tests.c new file mode 100644 index 0000000..9302f72 --- /dev/null +++ b/tests/libsepol-tests.c @@ -0,0 +1,118 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <CUnit/Basic.h> +#include <CUnit/Console.h> +#include <CUnit/TestDB.h> + +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> + +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; +} diff --git a/tests/policies/support/misc_macros.spt b/tests/policies/support/misc_macros.spt new file mode 100644 index 0000000..5fadd0f --- /dev/null +++ b/tests/policies/support/misc_macros.spt @@ -0,0 +1,23 @@ + +######################################## +# +# 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 diff --git a/tests/policies/test-cond/refpolicy-base.conf b/tests/policies/test-cond/refpolicy-base.conf new file mode 100644 index 0000000..60da11a --- /dev/null +++ b/tests/policies/test-cond/refpolicy-base.conf @@ -0,0 +1,1939 @@ +class 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; + 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 diff --git a/tests/policies/test-deps/base-metreq.conf b/tests/policies/test-deps/base-metreq.conf new file mode 100644 index 0000000..9b7ade5 --- /dev/null +++ b/tests/policies/test-deps/base-metreq.conf @@ -0,0 +1,519 @@ +# 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; + +# 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) + + + + diff --git a/tests/policies/test-deps/base-notmetreq.conf b/tests/policies/test-deps/base-notmetreq.conf new file mode 100644 index 0000000..cf6aa0a --- /dev/null +++ b/tests/policies/test-deps/base-notmetreq.conf @@ -0,0 +1,506 @@ +# 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 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) + + + + diff --git a/tests/policies/test-deps/modreq-attr-global.conf b/tests/policies/test-deps/modreq-attr-global.conf new file mode 100644 index 0000000..92f6b30 --- /dev/null +++ b/tests/policies/test-deps/modreq-attr-global.conf @@ -0,0 +1,10 @@ +module modreq_attr_global 1.0; + +require { + attribute attr_req; +} + +type mod_global_t; + +type new_t, attr_req; + diff --git a/tests/policies/test-deps/modreq-attr-opt.conf b/tests/policies/test-deps/modreq-attr-opt.conf new file mode 100644 index 0000000..b970c1d --- /dev/null +++ b/tests/policies/test-deps/modreq-attr-opt.conf @@ -0,0 +1,16 @@ +module 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; +} diff --git a/tests/policies/test-deps/modreq-bool-global.conf b/tests/policies/test-deps/modreq-bool-global.conf new file mode 100644 index 0000000..4ef0cc9 --- /dev/null +++ b/tests/policies/test-deps/modreq-bool-global.conf @@ -0,0 +1,15 @@ +module 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 }; +} diff --git a/tests/policies/test-deps/modreq-bool-opt.conf b/tests/policies/test-deps/modreq-bool-opt.conf new file mode 100644 index 0000000..27af4f2 --- /dev/null +++ b/tests/policies/test-deps/modreq-bool-opt.conf @@ -0,0 +1,22 @@ +module 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 }; + } +} diff --git a/tests/policies/test-deps/modreq-obj-global.conf b/tests/policies/test-deps/modreq-obj-global.conf new file mode 100644 index 0000000..e9eba77 --- /dev/null +++ b/tests/policies/test-deps/modreq-obj-global.conf @@ -0,0 +1,13 @@ +module 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 }; + diff --git a/tests/policies/test-deps/modreq-obj-opt.conf b/tests/policies/test-deps/modreq-obj-opt.conf new file mode 100644 index 0000000..67a41a4 --- /dev/null +++ b/tests/policies/test-deps/modreq-obj-opt.conf @@ -0,0 +1,20 @@ +module 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 }; +} diff --git a/tests/policies/test-deps/modreq-perm-global.conf b/tests/policies/test-deps/modreq-perm-global.conf new file mode 100644 index 0000000..941ca96 --- /dev/null +++ b/tests/policies/test-deps/modreq-perm-global.conf @@ -0,0 +1,10 @@ +module 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 }; diff --git a/tests/policies/test-deps/modreq-perm-opt.conf b/tests/policies/test-deps/modreq-perm-opt.conf new file mode 100644 index 0000000..43a3f97 --- /dev/null +++ b/tests/policies/test-deps/modreq-perm-opt.conf @@ -0,0 +1,18 @@ +module 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 }; +} diff --git a/tests/policies/test-deps/modreq-role-global.conf b/tests/policies/test-deps/modreq-role-global.conf new file mode 100644 index 0000000..01fd3ec --- /dev/null +++ b/tests/policies/test-deps/modreq-role-global.conf @@ -0,0 +1,13 @@ +module 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; + diff --git a/tests/policies/test-deps/modreq-role-opt.conf b/tests/policies/test-deps/modreq-role-opt.conf new file mode 100644 index 0000000..532a77e --- /dev/null +++ b/tests/policies/test-deps/modreq-role-opt.conf @@ -0,0 +1,17 @@ +module 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; +} diff --git a/tests/policies/test-deps/modreq-type-global.conf b/tests/policies/test-deps/modreq-type-global.conf new file mode 100644 index 0000000..e5704a3 --- /dev/null +++ b/tests/policies/test-deps/modreq-type-global.conf @@ -0,0 +1,12 @@ +module 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 }; diff --git a/tests/policies/test-deps/modreq-type-opt.conf b/tests/policies/test-deps/modreq-type-opt.conf new file mode 100644 index 0000000..65071d7 --- /dev/null +++ b/tests/policies/test-deps/modreq-type-opt.conf @@ -0,0 +1,16 @@ +module 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 }; +}
\ No newline at end of file diff --git a/tests/policies/test-deps/module.conf b/tests/policies/test-deps/module.conf new file mode 100644 index 0000000..1971e4c --- /dev/null +++ b/tests/policies/test-deps/module.conf @@ -0,0 +1,20 @@ +module 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 }; +} diff --git a/tests/policies/test-deps/small-base.conf b/tests/policies/test-deps/small-base.conf new file mode 100644 index 0000000..7c1cbe4 --- /dev/null +++ b/tests/policies/test-deps/small-base.conf @@ -0,0 +1,511 @@ +# 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) + + + + diff --git a/tests/policies/test-expander/alias-base.conf b/tests/policies/test-expander/alias-base.conf new file mode 100644 index 0000000..f3d0a6c --- /dev/null +++ b/tests/policies/test-expander/alias-base.conf @@ -0,0 +1,498 @@ +# 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 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) + + + + diff --git a/tests/policies/test-expander/alias-module.conf b/tests/policies/test-expander/alias-module.conf new file mode 100644 index 0000000..72d791e --- /dev/null +++ b/tests/policies/test-expander/alias-module.conf @@ -0,0 +1,8 @@ +module my_module 1.0; + +require { + type alias_check_3_t; +} + +typealias alias_check_3_t alias alias_check_3_a; + diff --git a/tests/policies/test-expander/base-base-only.conf b/tests/policies/test-expander/base-base-only.conf new file mode 100644 index 0000000..80b87cc --- /dev/null +++ b/tests/policies/test-expander/base-base-only.conf @@ -0,0 +1,43 @@ +class 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 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) + + diff --git a/tests/policies/test-expander/module.conf b/tests/policies/test-expander/module.conf new file mode 100644 index 0000000..6186db7 --- /dev/null +++ b/tests/policies/test-expander/module.conf @@ -0,0 +1,228 @@ +module 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; +} + diff --git a/tests/policies/test-expander/role-base.conf b/tests/policies/test-expander/role-base.conf new file mode 100644 index 0000000..219987c --- /dev/null +++ b/tests/policies/test-expander/role-base.conf @@ -0,0 +1,479 @@ +# 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 types role_check_1_1_t; + +######## +type fs_t; +type system_t; +type user_t; +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) + + + + diff --git a/tests/policies/test-expander/role-module.conf b/tests/policies/test-expander/role-module.conf new file mode 100644 index 0000000..1cc5d22 --- /dev/null +++ b/tests/policies/test-expander/role-module.conf @@ -0,0 +1,9 @@ +module 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; diff --git a/tests/policies/test-expander/small-base.conf b/tests/policies/test-expander/small-base.conf new file mode 100644 index 0000000..6f45a28 --- /dev/null +++ b/tests/policies/test-expander/small-base.conf @@ -0,0 +1,718 @@ +# 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 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 }; +} + +# 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) + + + + diff --git a/tests/policies/test-expander/user-base.conf b/tests/policies/test-expander/user-base.conf new file mode 100644 index 0000000..660152e --- /dev/null +++ b/tests/policies/test-expander/user-base.conf @@ -0,0 +1,482 @@ +# 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 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 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) + + + + diff --git a/tests/policies/test-expander/user-module.conf b/tests/policies/test-expander/user-module.conf new file mode 100644 index 0000000..4ef3e62 --- /dev/null +++ b/tests/policies/test-expander/user-module.conf @@ -0,0 +1,9 @@ +module my_module 1.0; + +require { + class file {read write}; +ifdef(`enable_mls',` + user user_check_1; +') +} + diff --git a/tests/policies/test-hooks/cmp_policy.conf b/tests/policies/test-hooks/cmp_policy.conf new file mode 100644 index 0000000..ec1e234 --- /dev/null +++ b/tests/policies/test-hooks/cmp_policy.conf @@ -0,0 +1,471 @@ +# 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) + + + + diff --git a/tests/policies/test-hooks/module_add_role_allow_trans.conf b/tests/policies/test-hooks/module_add_role_allow_trans.conf new file mode 100644 index 0000000..c6ecd83 --- /dev/null +++ b/tests/policies/test-hooks/module_add_role_allow_trans.conf @@ -0,0 +1,15 @@ +module 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; diff --git a/tests/policies/test-hooks/module_add_symbols.conf b/tests/policies/test-hooks/module_add_symbols.conf new file mode 100644 index 0000000..cf56e18 --- /dev/null +++ b/tests/policies/test-hooks/module_add_symbols.conf @@ -0,0 +1,12 @@ +module 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 }; +') diff --git a/tests/policies/test-hooks/small-base.conf b/tests/policies/test-hooks/small-base.conf new file mode 100644 index 0000000..ec1e234 --- /dev/null +++ b/tests/policies/test-hooks/small-base.conf @@ -0,0 +1,471 @@ +# 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) + + + + diff --git a/tests/policies/test-linker/module1.conf b/tests/policies/test-linker/module1.conf new file mode 100644 index 0000000..7cfb6cb --- /dev/null +++ b/tests/policies/test-linker/module1.conf @@ -0,0 +1,138 @@ +module 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 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 types g_m1_type_2; + +#add type to base optional role test +role o1_b_role_2 types g_m1_type_1; + +#optional base role w/ adds in 2 modules +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 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 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 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; + + +} diff --git a/tests/policies/test-linker/module2.conf b/tests/policies/test-linker/module2.conf new file mode 100644 index 0000000..3820cb7 --- /dev/null +++ b/tests/policies/test-linker/module2.conf @@ -0,0 +1,62 @@ +module 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 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 types g_m2_type_2; + +#optional base role w/ adds in 2 modules +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 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; + +} diff --git a/tests/policies/test-linker/small-base.conf b/tests/policies/test-linker/small-base.conf new file mode 100644 index 0000000..2f166c9 --- /dev/null +++ b/tests/policies/test-linker/small-base.conf @@ -0,0 +1,593 @@ +# 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 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 types o1_b_type_1; + + 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 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 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) + + + + diff --git a/tests/test-common.c b/tests/test-common.c new file mode 100644 index 0000000..058b743 --- /dev/null +++ b/tests/test-common.c @@ -0,0 +1,262 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Chad Sellers <csellers@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * 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 <sepol/policydb/avrule_block.h> + +#include <CUnit/Basic.h> + +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); +} diff --git a/tests/test-common.h b/tests/test-common.h new file mode 100644 index 0000000..5a1e650 --- /dev/null +++ b/tests/test-common.h @@ -0,0 +1,78 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Chad Sellers <csellers@tresys.com> + * + * 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 <sepol/policydb/policydb.h> + +/* 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 diff --git a/tests/test-cond.c b/tests/test-cond.c new file mode 100644 index 0000000..32bf6f1 --- /dev/null +++ b/tests/test-cond.c @@ -0,0 +1,95 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/conditional.h> + +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; +} diff --git a/tests/test-cond.h b/tests/test-cond.h new file mode 100644 index 0000000..702d9e0 --- /dev/null +++ b/tests/test-cond.h @@ -0,0 +1,30 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <CUnit/Basic.h> + +int cond_test_init(void); +int cond_test_cleanup(void); +int cond_add_tests(CU_pSuite suite); + +#endif diff --git a/tests/test-deps.c b/tests/test-deps.c new file mode 100644 index 0000000..e7d2beb --- /dev/null +++ b/tests/test-deps.c @@ -0,0 +1,302 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> + +#include <stdlib.h> + +/* 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 <sepol/debug.h> +#include <sepol/handle.h> + +#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; +} diff --git a/tests/test-deps.h b/tests/test-deps.h new file mode 100644 index 0000000..fbd2ace --- /dev/null +++ b/tests/test-deps.h @@ -0,0 +1,30 @@ +/* + * Author: Karl MacMillan <kmacmillan@tresys.com> + * + * 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 <CUnit/Basic.h> + +int deps_test_init(void); +int deps_test_cleanup(void); +int deps_add_tests(CU_pSuite suite); + +#endif diff --git a/tests/test-downgrade.c b/tests/test-downgrade.c new file mode 100644 index 0000000..1ee7ff4 --- /dev/null +++ b/tests/test-downgrade.c @@ -0,0 +1,273 @@ +/* + * Author: Mary Garvin <mgarvin@tresys.com> + * + * 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 <sepol/debug.h> +#include <sepol/handle.h> +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/conditional.h> +#include <limits.h> +#include <CUnit/Basic.h> + +#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; +} diff --git a/tests/test-downgrade.h b/tests/test-downgrade.h new file mode 100644 index 0000000..10a7c3b --- /dev/null +++ b/tests/test-downgrade.h @@ -0,0 +1,119 @@ +/* + * Author: Mary Garvin <mgarvin@tresys.com> + * + * 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 <CUnit/Basic.h> +#include <sepol/policydb/policydb.h> + +/* + * 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 diff --git a/tests/test-expander-attr-map.c b/tests/test-expander-attr-map.c new file mode 100644 index 0000000..5c24ced --- /dev/null +++ b/tests/test-expander-attr-map.c @@ -0,0 +1,105 @@ +/* + * Authors: Chad Sellers <csellers@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <CUnit/Basic.h> +#include <stdlib.h> + +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")); +} diff --git a/tests/test-expander-attr-map.h b/tests/test-expander-attr-map.h new file mode 100644 index 0000000..6a10089 --- /dev/null +++ b/tests/test-expander-attr-map.h @@ -0,0 +1,26 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 diff --git a/tests/test-expander-roles.c b/tests/test-expander-roles.c new file mode 100644 index 0000000..ecfa88e --- /dev/null +++ b/tests/test-expander-roles.c @@ -0,0 +1,37 @@ +/* + * Authors: Chad Sellers <csellers@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <CUnit/Basic.h> +#include <stdlib.h> + +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); +} diff --git a/tests/test-expander-roles.h b/tests/test-expander-roles.h new file mode 100644 index 0000000..380d2ef --- /dev/null +++ b/tests/test-expander-roles.h @@ -0,0 +1,27 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Author: Chris PeBenito <cpebenito@tresys.com> + * + * 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 diff --git a/tests/test-expander-users.c b/tests/test-expander-users.c new file mode 100644 index 0000000..549492b --- /dev/null +++ b/tests/test-expander-users.c @@ -0,0 +1,75 @@ +/* + * Authors: Chad Sellers <csellers@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * Chris PeBenito <cpebenito@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <CUnit/Basic.h> +#include <stdlib.h> + +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); +} diff --git a/tests/test-expander-users.h b/tests/test-expander-users.h new file mode 100644 index 0000000..cb12143 --- /dev/null +++ b/tests/test-expander-users.h @@ -0,0 +1,27 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Author: Chris PeBenito <cpebenito@tresys.com> + * + * 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 diff --git a/tests/test-expander.c b/tests/test-expander.c new file mode 100644 index 0000000..ded1d9d --- /dev/null +++ b/tests/test-expander.c @@ -0,0 +1,218 @@ +/* + * Authors: Chad Sellers <csellers@tresys.com> + * Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/expand.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/conditional.h> +#include <limits.h> +#include <stdlib.h> + +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; +} diff --git a/tests/test-expander.h b/tests/test-expander.h new file mode 100644 index 0000000..5964133 --- /dev/null +++ b/tests/test-expander.h @@ -0,0 +1,30 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <CUnit/Basic.h> + +int expander_test_init(void); +int expander_test_cleanup(void); +int expander_add_tests(CU_pSuite suite); + +#endif diff --git a/tests/test-linker-cond-map.c b/tests/test-linker-cond-map.c new file mode 100644 index 0000000..0ef0d69 --- /dev/null +++ b/tests/test-linker-cond-map.c @@ -0,0 +1,159 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/conditional.h> + +#include <CUnit/Basic.h> +#include <stdlib.h> + +/* 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); +} diff --git a/tests/test-linker-cond-map.h b/tests/test-linker-cond-map.h new file mode 100644 index 0000000..148c6f6 --- /dev/null +++ b/tests/test-linker-cond-map.h @@ -0,0 +1,27 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 diff --git a/tests/test-linker-roles.c b/tests/test-linker-roles.c new file mode 100644 index 0000000..42f92d3 --- /dev/null +++ b/tests/test-linker-roles.c @@ -0,0 +1,206 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> + +#include <CUnit/Basic.h> +#include <stdlib.h> + +/* 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); +} diff --git a/tests/test-linker-roles.h b/tests/test-linker-roles.h new file mode 100644 index 0000000..f7407df --- /dev/null +++ b/tests/test-linker-roles.h @@ -0,0 +1,29 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> + +extern void base_role_tests(policydb_t * base); +extern void module_role_tests(policydb_t * base); + +#endif diff --git a/tests/test-linker-types.c b/tests/test-linker-types.c new file mode 100644 index 0000000..94f16ac --- /dev/null +++ b/tests/test-linker-types.c @@ -0,0 +1,317 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * Chad Sellers <csellers@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> + +#include <CUnit/Basic.h> +#include <stdlib.h> + +/* 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); + +} diff --git a/tests/test-linker-types.h b/tests/test-linker-types.h new file mode 100644 index 0000000..0c860eb --- /dev/null +++ b/tests/test-linker-types.h @@ -0,0 +1,27 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 diff --git a/tests/test-linker.c b/tests/test-linker.c new file mode 100644 index 0000000..d08f219 --- /dev/null +++ b/tests/test-linker.c @@ -0,0 +1,154 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <sepol/policydb/policydb.h> +#include <sepol/policydb/link.h> +#include <sepol/policydb/conditional.h> +#include <sepol/policydb/expand.h> +#include <limits.h> +#include <stdlib.h> + +#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; +} diff --git a/tests/test-linker.h b/tests/test-linker.h new file mode 100644 index 0000000..16339a0 --- /dev/null +++ b/tests/test-linker.h @@ -0,0 +1,30 @@ +/* + * Author: Joshua Brindle <jbrindle@tresys.com> + * + * 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 <CUnit/Basic.h> + +int linker_test_init(void); +int linker_test_cleanup(void); +int linker_add_tests(CU_pSuite suite); + +#endif diff --git a/utils/Makefile b/utils/Makefile new file mode 100644 index 0000000..6864114 --- /dev/null +++ b/utils/Makefile @@ -0,0 +1,24 @@ +# 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: + diff --git a/utils/chkcon.c b/utils/chkcon.c new file mode 100644 index 0000000..4c23d4c --- /dev/null +++ b/utils/chkcon.c @@ -0,0 +1,42 @@ +#include <sepol/sepol.h> +#include <unistd.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +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); +} |