pax_global_header00006660000000000000000000000064140204547770014524gustar00rootroot0000000000000052 comment=4758cdf803d93274f49cb6445cb2bab527d6549f setools-4.4.0/000077500000000000000000000000001402045477700132215ustar00rootroot00000000000000setools-4.4.0/.coveragerc000066400000000000000000000003041402045477700153370ustar00rootroot00000000000000#coverage.py configuration [run] source = setools plugins = Cython.Coverage [report] exclude_lines = pragma: no cover def __repr__ raise NotImplementedError return NotImplemented setools-4.4.0/.github/000077500000000000000000000000001402045477700145615ustar00rootroot00000000000000setools-4.4.0/.github/workflows/000077500000000000000000000000001402045477700166165ustar00rootroot00000000000000setools-4.4.0/.github/workflows/stale.yml000066400000000000000000000013671402045477700204600ustar00rootroot00000000000000name: Mark stale issues and pull requests on: schedule: - cron: "30 1 * * *" jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v3 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has not had any recent activity. It will be closed in 7 days if it makes no further progress.' close-issue-message: 'Closing stale PR.' stale-pr-message: 'This PR has not had any recent activity. It will be closed in 7 days if it makes no further progress.' close-pr-message: 'Closing stale PR.' stale-issue-label: 'stale' stale-pr-label: 'stale' exempt-issue-labels: 'question,help-wanted' exempt-pr-labels: 'question,external-bug' setools-4.4.0/.github/workflows/tests.yml000066400000000000000000000046761402045477700205200ustar00rootroot00000000000000name: Build tests on: [push, pull_request] env: SELINUX_USERSPACE_VERSION: 3.2 jobs: build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: build-opts: - {python: 3.6, tox: py36} - {python: 3.7, tox: py37} - {python: 3.8, tox: py38} - {python: 3.6, tox: pep8} - {python: 3.6, tox: lint} - {python: 3.6, tox: mypy} #- {python: 3.6, tox: coverage} steps: - uses: actions/checkout@v2 # This should be the minimum required Python version to build refpolicy. - name: Set up Python ${{ matrix.build-opts.python }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.build-opts.python }} - name: Install dependencies run: | sudo apt-get update -qq sudo apt-get install -qqy \ bison \ flex \ gettext \ libaudit-dev \ libbz2-dev \ libpcre3-dev \ python3-pip sudo pip3 install \ cython \ setuptools \ tox - name: Configure environment run: | USERSPACE_SRC=/tmp/selinux-src SEPOL_SRC=${USERSPACE_SRC}/libsepol LIBSEPOLA=${SEPOL_SRC}/src/libsepol.a echo "USERSPACE_SRC=$USERSPACE_SRC" >> $GITHUB_ENV echo "SEPOL_SRC=${SEPOL_SRC}" >> $GITHUB_ENV echo "LIBSEPOLA=${LIBSEPOLA}" >> $GITHUB_ENV echo "SELINUX_SRC=${USERSPACE_SRC}/libselinux" >> $GITHUB_ENV echo "CHECKPOLICY_SRC=${USERSPACE_SRC}/checkpolicy" >> $GITHUB_ENV - name: Build toolchain run: | # Download current SELinux userspace tools and libraries git clone https://github.com/SELinuxProject/selinux.git ${USERSPACE_SRC} -b ${SELINUX_USERSPACE_VERSION} # Compile SELinux userspace make -C ${SEPOL_SRC} make CFLAGS="-O2 -pipe -fPIC -Wall -I${SEPOL_SRC}/include" LDFLAGS="-L${SEPOL_SRC}/src" -C ${SELINUX_SRC} make CFLAGS="-O2 -pipe -fPIC -Wall -I${SEPOL_SRC}/include" -C ${CHECKPOLICY_SRC} - name: Set up setools for CI build run: | sed -i \ -e "/Wwrite-strings/s/,/, '-Wno-maybe-uninitialized',/" \ -e "s/-Wno-cast-function-type/-Wno-missing-include-dirs/" \ setup.py - name: Run test run: | export LD_LIBRARY_PATH="${SEPOL_SRC}/src:${SELINUX_SRC}/src:${LD_LIBRARY_PATH}" tox -vv -e ${{ matrix.build-opts.tox }} setools-4.4.0/.gitignore000066400000000000000000000003531402045477700152120ustar00rootroot00000000000000/.eggs /.idea /.mypy_cache /.vscode /build /dist /setools.egg-info /venv *.pyc *.pyo /setools/policyrep.c *.so # Qt Generated Help files qhc/apol.qch qhc/apol.qhc # Generated by tox /.tox # Generated by coverage /htmlcov /.coverage setools-4.4.0/.mypy.ini000066400000000000000000000004161402045477700147770ustar00rootroot00000000000000[mypy] no_implicit_optional = True pretty = True # NetworkX does not have annotations [mypy-networkx] ignore_missing_imports = True [mypy-networkx.*] ignore_missing_imports = True [mypy-PyQt5.*] ignore_missing_imports = True [mypy-sip] ignore_missing_imports = True setools-4.4.0/.pylintrc000066400000000000000000000265651402045477700151040ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. jobs=0 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist=setools.policyrep # Allow optimization of some AST trees. This will activate a peephole AST # optimizer, which will apply various small optimizations. For instance, it can # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting # AST will be different than the one from reality. optimize-ast=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # format: enforced by pep8 tool disable=I,logging-format-interpolation,format,similarities [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,s,t,ex,fs,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=no # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Naming hint for constant names const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for function names function-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for variable names variable-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [ELIF] # Maximum number of nested blocks for function / method body max-nested-blocks=5 [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SPELLING] # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [FORMAT] # Maximum number of characters on a single line. max-line-length=100 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). This supports can work # with qualified names. ignored-classes= # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_,_cb [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=optparse # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [DESIGN] # Maximum number of arguments for function / method max-args=20 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=20 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=15 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=20 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict,_fields,_replace,_source,_make [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception setools-4.4.0/COPYING000066400000000000000000000006611402045477700142570ustar00rootroot00000000000000The intent is to allow free use of this source code. All programs' source files are copyright protected and freely distributed under the GNU General Public License (see COPYING.GPL). All library source files are copyright under the GNU Lesser General Public License (see COPYING.LGPL). All files distributed with this package indicate the appropriate license to use with that file. Absolutely no warranty is provided or implied. setools-4.4.0/COPYING.GPL000066400000000000000000000432541402045477700147050ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, 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. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. setools-4.4.0/COPYING.LGPL000066400000000000000000000636421402045477700150240ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! setools-4.4.0/ChangeLog000066400000000000000000000157721402045477700150070ustar00rootroot00000000000000*setools-4.4.0 (5 Mar 2021) * Updated policy representation to handle policydb version 33, compressed filename transitions. * Changed apol tab registry to use metaclasses rather than having a multiple static dictionaries in the code. * Fixed bug in queries where checks that permissions were part of the specified object class would incorrectly raise exceptions when the object class criteria is a regex. * Reduced aggressiveness of default compiler flags. Since the C code is generated by Cython, there typically isn't anything SETools can do when Cython causes compiler warnings. * Added type annotations to the code and added static type checking for continuous integration tests. * Added support for old Boolean name substitution in seinfo and sesearch. * Added sechecker tool which is a configuration file driven analysis tool. *setools-4.3.0 (1 Apr 2020) * Revised sediff method for TE rules. This drastically reduced memory and run time. * Added infiniband context support to seinfo, sediff, and apol. * Added apol configuration for location of Qt assistant. * Fixed sediff issue where properties header would display when not requested. * Fixed sediff issue with type_transition file name comparison. * Fixed permission map socket sendto information flow direction. * Added methods to TypeAttribute class to make it a complete Python collection. * Genfscon now will look up classes rather than using fixed values which were dropped from libsepol. *setools-4.2.2 (15 Jun 2019) * Remove source policy references from man pages, as loading source policies is no longer supported. * Fixed a performance regression in alias loading after alias dereferencing fixes in 4.2.1. *setools-4.2.1 (4 Feb 2019) * Set SIGPIPE handler for CLI tools. * Fixed alias dereferencing in TypeQuery and type, category, and sensitivity lookups. * Fixed sediff bug for rendering modified nodecons. * Fixed devicetreecon count output. * Fixed policy target platform check. * Fixed bug in creating permission set intersection in apol. *setools-4.2.0 (10 Nov 2018) This release focused on improving performance and reducing memory usage. A Cython-based policy representation replaced the Python/SWIG/static-linked-libsepol implemention. SETools no longer statically links to libsepol, though it is strongly suggested that users rebuild SETools after updating libsepol, in case the policy structure changes. Building on the policy representation change, refinements in sediff yielded as much as a 90% reduction in memory use, depending on the policies. This release of SETools has different dependencies than previous versions. See README.md for more details. Support for Python 2.7 was dropped because all current SELinux-supporting distributions provide Python 3. Other smaller changes included: * Added support for SCTP portcons. * Updated permission maps. * Policy symbol names are now available as the name attribute (e.g. Boolean.name, Type.name, etc.) * Revised some apol layouts to increase the size of text entry fields. * Revised package structure to make policyrep a module of the setools package. * Moved constraint expression to its own class. * Made Conditional.evaluate() more useful and added BaseTERule.enabled() method to determine if a rule is enabled. Changes since v4.2.0-rc: * Restored missing statement() methods in some policyrep classes * Fixed NULL pointer dereference when iterating over type attributes when the policy has none. * Added xdp_socket permission mapping. *setools-4.2.0-rc (29 Sep 2018) Changes since v4.2.0-beta: * Fixed performance regressions. * Made further memory usage improvements. * Fixed build issues with clean target and runtime_library_dirs. * Revised package structure to make policyrep a module of the setools package. * Symbol names are now available as the name attribute (e.g. Boolean.name, Type.name, etc.) * Fixed some apol layouts to increase the size of text fields. * Move constraint expression to its own class. * Made Conditional.evaluate() more useful and added BaseTERule.enabled() method to determine if a rule is enabled. *setools-4.2.0-beta (10 Jul 2018) Changes since v4.1.1: * Replaced the Python/SWIG/static-linked-libsepol policyrep module with a Cython implementation. This will have performance and memory-usage improvements and breaks the static linking to libsepol. * Significant memory usage reduction in sediff (approximately 60%, depending on the policies). * Added support for SCTP portcons. * Updated permission maps. * Support for Python 2.7 was dropped. This release of SETools has changed dependencies since 4.1.1. See README.md for more details. *setools-4.1.1 (5 Aug 2017) This release has three changes since 4.1.0: * Update for libsepol 2.7 * Update to permission maps * Fixes for apol help files *setools-4.1.0 (23 Jan 2017) This release primarily focused on adding features to apol, but has several library enhancements. There is also one important bugfix in sediff. There were no changes since 4.1.0-rc. Note This will not compile on the master branch of libsepol (what will be libsepol 2.7). A future release of SETools will have this support (when libsepol 2.7 is released). *setools-4.1.0-rc (11 Dec 2016) Library: * Implemented support for alternate install prefixes. * Implemented support for building setools with a locally-built libsepol. * Fixed an sediff bug with unioning rules after expansion. * Improved sediff memory usage. * Patch from Nicolas Iooss to make more stable output in TE rule permission lists. * Replaced string representations (e.g. rule types) with enumerations. Requires the enum34 (not enum) Python package if using Python < 3.4. Apol: * Implemented context menu option for exporting the information flow and domain transition analysis tree browser views. * Implemented CSV export of table results. * Implemented (clipboard) copy from table results. * Added missing "clear" button in object class query. * Implemented save/load settings for tabs. * Implemented save/load workspace (save all tabs settings). * Fixed include/exclude type dialog to keep its place when adding or removing types from an analysis. * Implemented filter on include/exclude type dialog to filter the lists by attribute. *setools-4.0.1 (17 May 2016) Library: * Fixed a compile error on 32bit systems. * Changed domain transition analysis output to use lists instead of generators. This fixes a display problem in apol's DTA browser. Apol: * Replaced icons with stock Qt icons to remove license issues with some distributions. Sesearch: * Changed xperm options to bring in line with sediff, e.g. --allowx changed to --allowxperm. Python's argument parser will still detect --allowx as an abbreviation of --allowxperm, so compatibility is preserved. *setools-4.0.0 (04 May 2016) First 4.0 release. SETools is reimplemented in Python. setools-4.4.0/KNOWN-BUGS000066400000000000000000000004771402045477700146060ustar00rootroot00000000000000The following is a list of known bugs with SETools. * A bug in NetworkX 1.8+ will output the following message to stderr if a type is valid, but not a node in a domain transition or information flow graph: 'Type' object is not iterable This message may be seen multiple times at the end of running unit tests. setools-4.4.0/MANIFEST.in000066400000000000000000000005031402045477700147550ustar00rootroot00000000000000include ChangeLog include COPYING* include man/* include qhc/* include setools/perm_map include setools/policyrep/*.pxd include setools/policyrep/*.pxi include setools/*.pyx include setoolsgui/*.ui include setoolsgui/apol/*.ui include setoolsgui/apol/apol.qhc include tests/*.conf include tests/*.py include tests/perm_map setools-4.4.0/README.md000066400000000000000000000134461402045477700145100ustar00rootroot00000000000000# SETools: Policy analysis tools for SELinux https://github.com/SELinuxProject/setools/wiki ## Overview This file describes SETools. SETools is a collection of graphical tools, command-line tools, and libraries designed to facilitate SELinux policy analysis. Please consult the KNOWN-BUGS file prior to reporting bugs. ## Installation SETools uses the Python setuptools build system to build, and install. As such it contains a setup.py script that will install the tools. To run SETools command line tools, the following packages are required: * Python 3.6+ * NetworkX 2.0+ * setuptools * libselinux * libsepol 3.2+ To run SETools graphical tools, the following packages are also required: * PyQt5 * qt5-assistant * qt-devel (only if rebuilding the help file) To build SETools, the following development packages are required, in addition to the development packages from the above list: * gcc * cython 0.27+ (0.29.14+ for Python 3.8) To run SETools unit tests, the following packages are required, in addition to the above dependencies: * tox (optional) ### Obtaining SETools SETools is included in most Linux distributions which support SELinux, such as Fedora, Red Hat Enterprise Linux, Gentoo, and Debian. Official releases of SETools may be freely downloaded from: https://github.com/SELinuxProject/setools/releases SETools source code is maintained within a GitHub repository. From the command line do: ``` $ git clone https://github.com/SELinuxProject/setools.git ``` You may also browse the GitHub repository at https://github.com/SELinuxProject/setools. The master branch has development code that may not be stable. Each release series is considered stable, and has its own branch, e.g. "4.0" for all 4.0.* releases. To checkout a stable branch, do: ``` $ git checkout 4.0 ``` Where `4.0` is the release series. Each release will have a tag. ### Building SETools for Local Use To use SETools locally, without installing it onto the system, unpack the official distribution or check out the git repository, and perform the following at the root: ``` $ python setup.py build_ext -i ``` This will compile the C portion of SETools locally, and then the tools can be ran from the current directory (e.g. ```./seinfo```). ### Rebuilding the Apol Help File For convenience, a prebuilt copy of the apol help data file is included. To rebuild this file, the Qt5 development tools are required (particularly, the ```qcollectiongenerator``` tool). At the root of the SETools sources, perform the following: ``` $ python setup.py build_qhc ``` ### Installing SETools Unpack the official distribution or check out the git repository, and perform the following at the root: ``` $ python setup.py build_ext $ python setup.py build $ python setup.py install ``` This will put the applications in /usr/bin, data files in /usr/share/setools, and libraries in /usr/lib/pythonX.Y/site-packages/setools. ### Building SETools with a Local Libsepol and Libselinux At times, SETools requires a newer libsepol than is available from distributions. To use a locally-built libsepol instead of the libsepol provided by the Linux distribution, build the libsepol sources and then set the USERSPACE_SRC environmental variable to the path to the root of SELinux userspace source tree. The libsepol and libselinux must already be compiled. ``` $ export USERSPACE_SRC=/home/user/src/selinux $ python setup.py build_ext $ python setup.py build $ python setup.py install ``` This feature assumes that the directory structure at $USERSPACE_SRC is the same as the SELinux userspace code checked out from GitHub. Since SETools is dynamically linked to libsepol and libselinux, you must specify the path to the libsepol/src and libselinux/src directories by using LD_LIBRARY_PATH so that the newer versions of the libraries are used. ``` $ export LD_LIBRARY_PATH="/home/user/src/selinux/libsepol/src:/home/user/src/selinux/libselinux/src" $ ./seinfo policy.31 $ ./sesearch -A sysadm_t policy.31 ``` ### Installation Options Please see `python setup.py --help` or `python setup.py install --help` for up-to-date information on build and install options, respectively. ### Unit Tests One goal for SETools is to provide confidence in the validity of the output for the tools. The unit tests for SETools can be run with the following command ``` $ python setup.py test ``` ## Features SETools encompasses a number of tools, both graphical and command line, and libraries. Many of the programs have help files accessible during runtime. ### Graphical tools Tool Name | Use ---------- | ------------------------------------------- apol | A Qt graphical analysis tool. Use it to perform various types of analyses. ### Command-line tools Tool Name | Use ---------- | ------------------------------------------- sechecker | Configuration file-driven automated analysis. sediff | Compare two policies to find differences. sedta | Perform domain transition analyses. seinfo | List policy components. seinfoflow | Perform information flow analyses. sesearch | Search rules (allow, type_transition, etc.) ### Analysis Libraries The SETools libraries are available for use in third-party applications. Although this is not officially supported, we will do our best to maintain API stability. ### Reporting bugs Bugs can be reported in the SETools GitHub issues tracker: https://github.com/SELinuxProject/setools/issues ### Copyright license The intent is to allow free use of this source code. All programs' source files are copyright protected and freely distributed under the GNU General Public License (see COPYING.GPL). All library source files are copyright under the GNU Lesser General Public License (see COPYING.LGPL). All files distributed with this package indicate the appropriate license to use. Absolutely no warranty is provided or implied. setools-4.4.0/apol000077500000000000000000000041601402045477700141030ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import sys import argparse import logging from PyQt5.QtWidgets import QApplication import setools import setoolsgui parser = argparse.ArgumentParser(description="Graphical SELinux policy analysis tool.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", nargs="?", help="Path to the SELinux policy to analyze.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG, filename="/dev/null") console_handler = logging.StreamHandler() if args.debug: console_handler.setLevel(logging.DEBUG) console_handler.setFormatter( logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|%(message)s')) elif args.verbose: console_handler.setLevel(logging.INFO) console_handler.setFormatter(logging.Formatter('%(message)s')) else: console_handler.setLevel(logging.WARNING) console_handler.setFormatter(logging.Formatter('%(message)s')) logging.getLogger().addHandler(console_handler) try: app = QApplication(sys.argv) mainwindow = setoolsgui.ApolMainWindow(args.policy) sys.exit(app.exec_()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/man/000077500000000000000000000000001402045477700137745ustar00rootroot00000000000000setools-4.4.0/man/apol.1000066400000000000000000000020721402045477700150120ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH apol 1 2016-02-20 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME apol \- Graphical SELinux policy analysis tool .SH SYNOPSIS \fBapol\fR [OPTIONS] [POLICY] .SH DESCRIPTION .PP \fBapol\fR is a graphical tool that allows the user to inspect and analyze aspects of an SELinux policy. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If not provided, \fBapol\fR will start with none loaded. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO sediff(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.4.0/man/ru/000077500000000000000000000000001402045477700144225ustar00rootroot00000000000000setools-4.4.0/man/ru/apol.1000066400000000000000000000042331402045477700154410ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH apol 1 2016-02-20 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ apol \- графичеÑÐºÐ°Ñ ÑƒÑ‚Ð¸Ð»Ð¸Ñ‚Ð° анализа политики SELinux .SH ОБЗОР \fBapol\fR [OPTIONS] [POLICY] .SH ОПИСÐÐИЕ .PP \fBapol\fR - графичеÑÐºÐ°Ñ ÑƒÑ‚Ð¸Ð»Ð¸Ñ‚Ð°, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет пользователю изучить и проанализировать аÑпекты политики SELinux. .SH ПОЛИТИКР.PP \fBapol\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Этот файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP ЕÑли файл политики не указан, она не будет загружена при запуÑке \fBapol\fR. .SH ПÐРÐМЕТРЫ .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ sediff(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/ru/sediff.1000066400000000000000000000173111402045477700157470ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sediff 1 2016-04-19 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ sediff \- утилита выÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ð¹ политик SELinux .SH ОБЗОР \fBsediff\fR [OPTIONS] [EXPRESSION] POLICY1 POLICY2 .SH ОПИСÐÐИЕ Определить Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ Ð´Ð²ÑƒÐ¼Ñ Ð¿Ð¾Ð»Ð¸Ñ‚Ð¸ÐºÐ°Ð¼Ð¸ SELinux. .SH ПОЛИТИКР.PP \fBsediff\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Это файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP Форматы политик могут не Ñовпадать. ЕÑли файл не указан, \fBsediff\fR выведет Ñообщение об ошибке и выполнит выход. .SH ВЫРÐЖЕÐИЯ .P Пользователь может указать выражение, перечиÑлÑющее Ñлементы политики, Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… Ñледует выÑвить. ЕÑли оно не указано, будут проверены вÑе поддерживаемые Ñлементы политики. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð² .IP "--common" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð½Ð°Ð±Ð¾Ñ€Ð¾Ð² общих разрешений. .IP "-c, --class" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ ÐºÐ»Ð°ÑÑов объектов. .IP "-t, --type" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ð¾Ð², ÑвÑзанных Ñ Ñ‚Ð¸Ð¿Ð°Ð¼Ð¸. .IP "-a, --attribute" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð², назначенных атрибутам. .IP "-r, --role" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð², разрешённых Ð´Ð»Ñ Ñ€Ð¾Ð»ÐµÐ¹. .IP "-u, --user" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð¾Ð»ÐµÐ¹, разрешённых Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹. .IP "-b, --bool" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ð¹ логичеÑких переключателей по умолчанию. .IP "--sensitivity" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ð¹ конфиденциальноÑти. .IP "--category" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ð¹ категорий. .IP "--level" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ð¹ уровней MLS. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» принудительного приÑÐ²Ð¾ÐµÐ½Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð² .IP "-A" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ñ… правил и раÑширенных разрешительных правил (allow и allowxperm). .IP "--allow" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ñ… правил. .IP "--auditallow" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--dontaudit" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» запрета Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--neverallow" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð·Ð°Ð¿Ñ€ÐµÑ‰Ð°ÑŽÑ‰Ð¸Ñ… правил. .IP "--allowxperm" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ñширенных разрешительных правил. .IP "--auditallowxperm" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ñширенных правил Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--dontauditxperm" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ñширенных правил запрета Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--neverallowxperm" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ñширенных запрещающих правил. .IP "-T, --type_trans" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» перехода типов. .IP "--type_member" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» учаÑÑ‚Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð². .IP "--type_change" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» Ñмены типов. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупом на оÑнове ролей (RBAC) .IP "--role_allow" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ñ‹Ñ… правил Ð´Ð»Ñ Ñ€Ð¾Ð»ÐµÐ¹. .IP "--role_trans" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» перехода ролей. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» MLS .IP "--range_trans" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» перехода диапазонов. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ð¹ .IP "--constrain" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡Ð¸Ð²Ð°ÑŽÑ‰Ð¸Ñ… правил. .IP "--mlsconstrain" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡Ð¸Ð²Ð°ÑŽÑ‰Ð¸Ñ… правил MLS. .IP "--validatetrans" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» проверки переходов. .IP "--mlsvalidatetrans" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» проверки переходов MLS. .SS Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций по проÑтавлению меток .IP "--initialsid" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ñ‹Ñ… инÑтрукций SID. .IP "--fs_use" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций fs_use_*. .IP "--genfscon" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций genfscon. .IP "--netifcon" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций netifcon. .IP "--nodecon" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций nodecon. .IP "--portcon" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций portcon. .SS Другие Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ .IP "--default" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций default_*. .IP "--property" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ ÑвойÑтв политик. Применимо только к двоичным политикам (верÑÐ¸Ñ Ð¿Ð¾Ð»Ð¸Ñ‚Ð¸ÐºÐ¸, включённаÑ/Ð¾Ñ‚ÐºÐ»ÑŽÑ‡Ñ‘Ð½Ð½Ð°Ñ ÑиÑтема MLS, значение параметра обработки неизвеÑтных разрешений). .IP "--polcap" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñтей политик. .IP "--typebounds" Ðайти Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¸Ð½Ñтрукций typebounds. .SH ПÐРÐМЕТРЫ .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--stats" ВывеÑти только ÑтатиÑтику различий. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH РÐЗЛИЧИЯ .PP .B sediff отноÑит Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ñлементов политики к одному из трёх видов. .RS .IP "added" Элемент ÑущеÑтвует только в изменённой политике. .IP "removed" Элемент ÑущеÑтвует только в иÑходной политике. .IP "modified" Элемент ÑущеÑтвует в обеих политиках, но его ÑемантичеÑкое значение изменилоÑÑŒ. Ðапример, клаÑÑ Ð¸Ð·Ð¼ÐµÐ½ÑетÑÑ Ð¿Ñ€Ð¸ добавлении или удалении одного или неÑкольких разрешений. .RE .PP .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ apol(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/ru/sedta.1000066400000000000000000000120521402045477700156040ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sedta 1 2016-02-20 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ sedta \- анализ доменных переходов в политиках SELinux .SH ОБЗОР \fBsedta\fR [OPTIONS] -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH ОПИСÐÐИЕ .PP \fBsedta\fR - утилита командной Ñтроки, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет пользователю анализировать доменные переходы в политике SELinux. .SH ПОЛИТИКР.PP \fBsedta\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Этот файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP .PP ЕÑли файл политики не указан, \fBsedta\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. ЕÑли политику не удалоÑÑŒ найти, \fBsedta\fR выведет Ñообщение об ошибке и выполнит выход. .SH ПÐРÐМЕТРЫ .SS Параметры анализа .IP "-p POLICY" Укажите политику, которую Ñледует проанализировать. ЕÑли политика не указана, \fBsedta\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. .IP "-s SOURCE" Укажите иÑходный тип, который Ñледует иÑпользовать при анализе доменных переходов. .IP "-t TARGET" Укажите целевой тип, который Ñледует иÑпользовать при анализе доменных переходов. Ð”Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтого параметра также потребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ алгоритм анализа. .SS Ðлгоритмы анализа \fBsedta\fR иÑпользует графовые алгоритмы Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¸Ð·Ð° путей доменных переходов политики SELinux. Следующие алгоритмы ÑвлÑÑŽÑ‚ÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿ÑƒÑ‚ÐµÐ¹ от иÑходного типа к целевому типу. .IP "-S" ВывеÑти кратчайший путь (пути) доменных переходов от иÑходного типа к целевому типу. ЕÑли неÑколько путей имеют одинаковую длину, будут показаны вÑе Ñти пути. .IP "-A LIMIT" ВывеÑти вÑе пути доменных переходов Ñ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтвом шагов вплоть до LIMIT. Ð’ завиÑимоÑти от количеÑтва ÑвÑзей в политике, Ñто может потребовать большого количеÑтва ÑиÑтемных реÑурÑов. .SS Опции анализа .IP -r Выполнить обратный анализ доменных переходов. Доменные переходы будут анализироватьÑÑ Ð´Ð»Ñ Ð²Ñ‹ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÑких доменов, а не дочерних доменов. .IP "-l LIMIT_TRANS" Указать макÑимальное количеÑтво доменных переходов, которое Ñледует вывеÑти. По умолчанию оно не ограничено. .IP EXCLUDE Разделённый пробелами ÑпиÑок типов, которые Ñледует иÑключить из анализа. .SS Общие параметры .IP "--stats" ВывеÑти графовую ÑтатиÑтику доменных переходов в конце анализа. .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ apol(1), sediff(1), seinfo(1), seinfoflow(1), sesearch(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/ru/seinfo.1000066400000000000000000000251051402045477700157720ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfo 1 2016-02-20 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ seinfo \- утилита Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ о политике SELinux .SH ОБЗОР \fBseinfo\fR [OPTIONS] [EXPRESSION] [POLICY] .SH ОПИСÐÐИЕ \fBseinfo\fR позволÑет пользователю опрашивать компоненты политики SELinux. .SH ПОЛИТИКР.PP \fBapol\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Этот файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP ЕÑли файл политики не указан, \fBseinfo\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. ЕÑли политику не удалоÑÑŒ найти, \fBseinfo\fR выведет Ñообщение об ошибке и выполнит выход. .SH ВЫРÐЖЕÐИЯ .P Возможно опроÑить один или неÑколько Ñледующих типов компонентов. ЕÑли Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ предоÑтавлены, будет выведена ÑтатиÑтика политики. .IP "-a [ATTR], --attribute [ATTR]" ВывеÑти ÑпиÑок атрибутов типов или, еÑли предоÑтавлÑетÑÑ ATTR, вывеÑти именованный атрибут. ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок типов, назначенных каждому отображаемому атрибуту. .IP "-b [BOOL], --bool [BOOL]" ВывеÑти ÑпиÑок логичеÑких переключателей или, еÑли предоÑтавлÑетÑÑ BOOL, вывеÑти именованный логичеÑкий переключатель. ИÑпользование \fI-x\fR позволÑет вывеÑти инÑтрукцию каждого отображаемого уÑловного логичеÑкого переключателÑ. .IP "-c [CLASS], --class [CLASS]" ВывеÑти ÑпиÑок клаÑÑов объектов или, еÑли предоÑтавлÑетÑÑ CLASS, вывеÑти именованный клаÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð². ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок разрешений Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ отображаемого клаÑÑа объектов. .IP "-r [ROLE], --role [ROLE]" ВывеÑти ÑпиÑок ролей или, еÑли предоÑтавлÑетÑÑ NAME, вывеÑти именованную роль. ИÑпользование \fI-x\fR позволÑет вывеÑти инÑтрукцию Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ отображаемой роли. .IP "-t [TYPE], --type [TYPE]" ВывеÑти ÑпиÑок типов или, еÑли предоÑтавлÑетÑÑ TYPE, вывеÑти именованный тип. ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок атрибутов, которые включают каждый отображаемый тип. .IP "-u [USER], --user [USER]" ВывеÑти ÑпиÑок пользователей или, еÑли предоÑтавлÑетÑÑ USER, вывеÑти именованного пользователÑ. ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок инÑтрукций Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ отображаемого пользователÑ. .IP "--category [CAT]" ВывеÑти ÑпиÑок категорий или, еÑли предоÑтавлÑетÑÑ CAT, вывеÑти именованную категорию. ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок уровней конфиденциальноÑти, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ может быть ÑвÑзана ÐºÐ°Ð¶Ð´Ð°Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÐ¼Ð°Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ. .IP "--common [COMMON]" ВывеÑти ÑпиÑок общих наборов разрешений или, еÑли предоÑтавлÑетÑÑ COMMON, вывеÑти именованный общий набор разрешений. ИÑпользование \fI-x\fR позволÑет вывеÑти ÑпиÑок разрешений в наборе. .IP "--constrain [CLASS]" ВывеÑти ÑпиÑок ограничений и инÑтрукций ограничений MLS или, еÑли предоÑтавлÑетÑÑ CLASS, вывеÑти вÑе Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ клаÑÑа объектов. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--default [CLASS]" ВывеÑти ÑпиÑок инÑтрукций default_* или, еÑли предоÑтавлÑетÑÑ CLASS, вывеÑти вÑе инÑтрукции default_* Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ клаÑÑа объектов. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--fs_use [FS_TYPE]" ВывеÑти ÑпиÑок инÑтрукций fs_use_* или, еÑли предоÑтавлÑетÑÑ FS_TYPE, вывеÑти инÑтрукцию Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ типа файловой ÑиÑтемы. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--genfscon [FS_TYPE]" ВывеÑти ÑпиÑок инÑтрукций genfscon или, еÑли предоÑтавлÑетÑÑ FS_TYPE, вывеÑти инÑтрукцию Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ типа файловой ÑиÑтемы. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--initialsid [NAME]" ВывеÑти ÑпиÑок начальных SID или, еÑли предоÑтавлÑетÑÑ NAME, вывеÑти именованный начальный идентификатор безопаÑноÑти. ИÑпользование \fI-x\fR позволÑет вывеÑти контекÑÑ‚, назначенный каждому отображаемому идентификатору безопаÑноÑти. .IP "--netifcon [DEVICE]" ВывеÑти ÑпиÑок контекÑтов netif или, еÑли предоÑтавлÑетÑÑ DEVICE, вывеÑти именованную инÑтрукцию Ð´Ð»Ñ Ñтого интерфейÑа. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--nodecon [ADDR]" ВывеÑти ÑпиÑок контекÑтов узлов или, еÑли предоÑтавлÑетÑÑ ADDR, вывеÑти именованную инÑтрукцию Ð´Ð»Ñ ÑƒÐ·Ð»Ð° Ñ Ñтим адреÑом. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--permissive [TYPE]" ВывеÑти разрешительные типы или, еÑли предоÑтавлÑетÑÑ TYPE, вывеÑти именованную инÑтрукцию, еÑли она ÑвлÑетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--polcap [NAME]" ВывеÑти возможноÑти политики или, еÑли указано NAME, вывеÑти именованную возможноÑть, еÑли она включена. ИÑпользование \fI-x\fR позволÑет вывеÑти инÑтрукцию. .IP "--portcon [PORTNUM[-PORTNUM]]" ВывеÑти ÑпиÑок контекÑтов портов или, еÑли предоÑтавлÑетÑÑ PORT или диапазон PORT, вывеÑти именованную инÑтрукцию Ð´Ð»Ñ Ð¿Ð¾Ñ€Ñ‚Ð°/диапазона портов. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--sensitivity [SENS]" ВывеÑти ÑпиÑок уровней конфиденциальноÑти или, еÑли предоÑтавлÑетÑÑ SENS, вывеÑти именованный уровень конфиденциальноÑти. ИÑпользование \fI-x\fR позволÑет вывеÑти инÑтрукцию Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑƒÑ€Ð¾Ð²Ð½Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð´ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð¾Ñти. .IP "--typebounds [BOUND_TYPE]" ВывеÑти ÑпиÑок инÑтрукций typebounds или, еÑли предоÑтавлÑетÑÑ BOUND_TYPE, вывеÑти инÑтрукцию Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ типа привÑзки. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--validatetrans [CLASS]" ВывеÑти ÑпиÑок правил validatetrans и MLS validatetrans или, еÑли предоÑтавлÑетÑÑ CLASS, вывеÑти вÑе Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð½Ð¾Ð³Ð¾ клаÑÑа объектов. Ð”Ð»Ñ Ñтого компонента нет раÑширенных Ñведений. .IP "--all" ВывеÑти вÑе компоненты. .SH ПÐРÐМЕТРЫ .IP "-x, --expand" ВывеÑти дополнительные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ каждом компоненте, ÑоответÑтвующем выражению. ПроÑмотрите опиÑание каждого компонента, чтобы узнать, какие ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñтавит Ñтот параметр. .IP "--flat" ИÑключить заголовки и отÑтупы в выводе. .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ apol(1), sediff(1), sedta(1), seinfoflow(1), sesearch(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/ru/seinfoflow.1000066400000000000000000000124611402045477700166630ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfoflow 1 2016-02-20 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ seinfoflow \- анализ потоков информации политик SELinux .SH ОБЗОР \fBseinfoflow\fR [OPTIONS] -m MAP -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH ОПИСÐÐИЕ .PP \fBseinfoflow\fR - утилита командной Ñтроки, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет пользователю анализировать потоки информации политики SELinux. .SH ПОЛИТИКР.PP \fBseinfoflow\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Этот файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP .PP ЕÑли файл политики не указан, \fBseinfoflow\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. ЕÑли политику не удалоÑÑŒ найти, \fBseinfoflow\fR выведет Ñообщение об ошибке и выполнит выход. .SH ПÐРÐМЕТРЫ .SS Параметры анализа .IP "-p POLICY" Укажите политику, которую Ñледует проанализировать. ЕÑли политика не указана, \fBseinfoflow\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. .IP "-m MAP" Укажите путь к файлу ÑоответÑтвий разрешений, который Ñледует иÑпользовать при анализе потоков информации. .IP "-s SOURCE" Укажите иÑходный тип, который Ñледует иÑпользовать при анализе потоков информации. .IP "-t TARGET" Укажите целевой тип, который Ñледует иÑпользовать при анализе потоков информации. Ð”Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтого параметра также потребуетÑÑ ÑƒÐºÐ°Ð·Ð°Ñ‚ÑŒ алгоритм анализа. .SS Ðлгоритмы анализа \fBseinfoflow\fR иÑпользует графовые алгоритмы Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¸Ð·Ð° путей потоков информации политики SELinux. Следующие алгоритмы ÑвлÑÑŽÑ‚ÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿ÑƒÑ‚ÐµÐ¹ от иÑходного типа к целевому типу. .IP "-S" ВывеÑти кратчайший путь (пути) потоков информации от иÑходного типа к целевому типу. ЕÑли неÑколько путей имеют одинаковую длину, будут показаны вÑе Ñти пути. .IP "-A LIMIT" ВывеÑти вÑе пути потоков информации Ñ ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑтвом шагов вплоть до LIMIT. Ð’ завиÑимоÑти от количеÑтва ÑвÑзей в политике, при уÑтановке Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð² значение 5 или больше может потребоватьÑÑ Ð¾Ñ‡ÐµÐ½ÑŒ большое количеÑтво ÑиÑтемных реÑурÑов. .SS Опции анализа .IP "-w MIN_WEIGHT" Указать минимальный Ð²ÐµÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ, который Ñледует учитывать Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¸Ð·Ð° (1-10). По умолчанию: 3. .IP "-l LIMIT_FLOWS" Указать макÑимальное количеÑтво потоков информации, которое Ñледует вывеÑти. По умолчанию оно не ограничено. .IP EXCLUDE Разделённый пробелами ÑпиÑок типов, которые Ñледует иÑключить из анализа. .SS Общие параметры .IP "--stats" ВывеÑти графовую ÑтатиÑтику потоков информации в конце анализа. .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ apol(1), sediff(1), sedta(1), seinfo(1), sesearch(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/ru/sesearch.1000066400000000000000000000176251402045477700163140ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sesearch 1 2016-04-19 "SELinux Project" "SETools: утилиты анализа политики SELinux" .SH ИМЯ sesearch \- утилита опроÑа политики SELinux .SH ОБЗОР \fBsesearch\fR [OPTIONS] [OPTIONS] [EXPRESSION] [POLICY] .SH ОПИСÐÐИЕ \fBsesearch\fR позволÑет пользователю выполнÑть поиÑк правил в политике SELinux. .SH ПОЛИТИКР.PP \fBsesearch\fR поддерживает загрузку политик SELinux в одном из двух форматов. .RS .IP "source:" Один текÑтовый файл, Ñодержащий иÑточник монолитной политики. Это файл обычно называетÑÑ policy.conf. .IP "binary:" Один файл, Ñодержащий двоичную политику. Ð’ ÑиÑтемах Linux название Ñтого файла обычно ÑоответÑтвует верÑии, например, \fIpolicy.30\fR. Ð’ ÑиÑтемах Android Ñтот файл обычно называетÑÑ \fIsepolicy\fR. .RE .PP ЕÑли файл политики не указан, \fBsesearch\fR выполнит поиÑк политики, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÑетÑÑ Ð² текущей ÑиÑтеме. ЕÑли политику не удалоÑÑŒ найти, \fBsesearch\fR выведет Ñообщение об ошибке и выполнит выход. .SH ВЫРÐЖЕÐИЯ Пользователь может указать выражение, которое Ñодержит значение Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ð¿Ð¾Ð»Ñ (полей) в правиле. ЕÑли выражение не указано или Ñреди указанных полей нет тех, которые применимы к конкретному типу правил, вÑе правила Ñтого типа ÑчитаютÑÑ ÑоответÑтвующими выражению. .SS Типы правил принудительного приÑÐ²Ð¾ÐµÐ½Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð² .IP "-A" Ðайти разрешительные правила и раÑширенные разрешительные правила (allow и allowxperm). .IP "--allow" Ðайти разрешительные правила. .IP "--auditallow" Ðайти правила Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--dontaudit" Ðайти правила запрета Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--neverallow" Ðайти запрещающие правила. .IP "--allowxperm" Ðайти раÑширенные разрешительные правила. .IP "--auditallowxperm" Ðайти раÑширенные правила Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--dontauditxperm" Ðайти раÑширенные правила запрета Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñобытий. .IP "--neverallowxperm" Ðайти раÑширенные запрещающие правила. .IP "-T, --type_trans" Ðайти правила перехода типов. .IP "--type_member" Ðайти правила учаÑÑ‚Ð¸Ñ Ñ‚Ð¸Ð¿Ð¾Ð². .IP "--type_change" Ðайти правила Ñмены типов. .SS Типы правил ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупом на оÑнове ролей (RBAC) .IP "--role_allow" Ðайти разрешительные правила Ð´Ð»Ñ Ñ€Ð¾Ð»ÐµÐ¹. .IP "--role_trans" Ðайти правила перехода ролей. .SS Типы правил MLS .IP "--range_trans" Ðайти правила перехода диапазонов. .SS ÐŸÐ¾Ð»Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» .IP "-s NAME, --source NAME" Ðайти правила, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… NAME ÑвлÑетÑÑ Ð¸Ñходным типом/ролью. .IP "-t NAME, --target NAME" Ðайти правила, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… NAME ÑвлÑетÑÑ Ñ†ÐµÐ»ÐµÐ²Ñ‹Ð¼ типом/ролью. .IP "-D NAME, --default NAME" Ðайти правила, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… NAME ÑвлÑетÑÑ Ñ‚Ð¸Ð¿Ð¾Ð¼/ролью/уровнем по умолчанию. .IP "-c NAME, --class NAME" Ðайти правила, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… NAME ÑвлÑетÑÑ ÐºÐ»Ð°ÑÑом объектов. .IP "-p P1[,P2,...] --perm P1[,P2...]" Ðайти правила Ñ Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одним из указанных разрешений. ÐеÑколько разрешений можно указать в виде разделённого запÑтыми ÑпиÑка. .IP "-b BOOL[,B2,...], --bool BOOL[,B2,...]" Ðайти уÑловные правила, которые Ñодержат в Ñвоём уÑловном выражении именованный логичеÑкий переключатель. ÐеÑколько логичеÑких переключателей можно указать в виде разделённого запÑтыми ÑпиÑка. При иÑпользовании Ñтого параметра будут включены как правила в ÑпиÑках true, так и правила в ÑпиÑках false уÑловных конÑтрукций. .SS Параметры поиÑка Следующие дополнительные параметры изменÑÑŽÑ‚ ÑпоÑоб поиÑка. .IP "-ds" СоответÑтвующее правило должно иметь указанный иÑходный атрибут/тип/роль в Ñвном виде, а не ÑоответÑтвовать по Ñодержимому атрибута. .IP "-dt" СоответÑтвующее правило должно иметь указанный целевой атрибут/тип/роль в Ñвном виде, а не ÑоответÑтвовать по Ñодержимому атрибута. .IP "-eb" СоответÑтвующее правило должно иметь вÑе указанные логичеÑкие переключатели, а не ÑоответÑтвовать по каким-либо из указанных логичеÑких переключателей. .IP "-ep" СоответÑтвующее правило должно иметь вÑе указанные разрешениÑ, а не ÑоответÑтвовать по каким-либо из указанных разрешений. .IP "-rs" ИÑпользовать регулÑрное выражение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑоответÑÑ‚Ð²Ð¸Ñ Ð¸Ñходного типа/роли. .IP "-rt" ИÑпользовать регулÑрное выражение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑоответÑÑ‚Ð²Ð¸Ñ Ñ†ÐµÐ»ÐµÐ²Ð¾Ð³Ð¾ типа/роли. .IP "-rc" ИÑпользовать регулÑрное выражение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑоответÑÑ‚Ð²Ð¸Ñ ÐºÐ»Ð°ÑÑа объектов. .IP "-rd" ИÑпользовать регулÑрное выражение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑоответÑÑ‚Ð²Ð¸Ñ Ñ‚Ð¸Ð¿Ð°/роли по умолчанию. .IP "-rb" ИÑпользовать регулÑрное выражение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑоответÑÑ‚Ð²Ð¸Ñ Ð»Ð¾Ð³Ð¸Ñ‡ÐµÑких переключателей. .SH ПÐРÐМЕТРЫ .IP "-h, --help" ВывеÑти Ñправочные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸ выйти. .IP "--version" ВывеÑти ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ верÑии и выйти. .IP "-v, --verbose" ВывеÑти дополнительные информационные ÑообщениÑ. .IP "--debug" Включить отладочный вывод. .SH ОШИБКИ ПожалуйÑта, Ñообщайте об ошибках через ÑиÑтему отÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¾ÑˆÐ¸Ð±Ð¾Ðº SETools, https://github.com/SELinuxProject/setools/issues .SH СМОТРИТЕ ТÐКЖЕ apol(1), sediff(1), sedta(1), seinfo(1), seinfoflow(1) .SH ÐВТОРЫ Chris PeBenito . Перевод на руÑÑкий Ñзык выполнила ГераÑименко ОлеÑÑ . setools-4.4.0/man/sechecker.1000066400000000000000000000175471402045477700160300ustar00rootroot00000000000000.TH sechecker 1 2020-06-09 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME sechecker \- Configuration-driven automated SELinux policy analysis .SH SYNOPSIS \fBsechecker\fR [OPTIONS] config.ini [POLICY] .SH DESCRIPTION .PP \fBsechecker\fR is an automated SELinux policy analysis tool. It uses a configuration file to define one or more analysis checks. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If not provided, \fBsechecker\fR will attempt to locate and open the current policy running on the system. .SH OPTIONS .IP "-o " Output the results to the specified path instead of stdout. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH RETURN CODES \fBsechecker\fR has the following return codes: .TP .B 0 All checks passed. .TP .B 1 One or more checks failed. .TP .B 2 Error in the configuration file. .TP .B 3 Other errors, such as policy open error. .SH "CONFIGURATION FILE" The configuration file is in the .ini format. Each section is considered a check, with the configuration section name being the name of the check. All checks have the following options: .IP "check_type = " This selects the type of test be be used in this check. This is required. .IP "desc = " This is an optional text field. If set, the contents are printed in the output and is typically used to explain the purpose of the check. .IP "disable = " This is an optional text field. If it is set, the check will not run and the contents of this text will be added to the report to explain why the check was not ran. .SH "TYPE ENFORCEMENT ALLOW RULE ASSERTION" This checks for the nonexistence of type enforcement allow rules. The check_type is \fBassert_te\fR. It will run the query and any unexpected results from the query, removing any exempted sources or targets, will be listed as failures. Any expected results that are not seen will also be listed as failures. If a rule has an empty attribute, rendering it useless, it will be ignored. If a rule has an attribute, it will be considered a failure unless all of the member types are exempted. .PP Criteria options: .IP "source = " The source type/attribute criteria for the query. .IP "target = " The target type/attribute criteria for the query. .IP "tclass = [ ....]" A space-separated list of object class criteria for the query. .IP "perms = [ ....]" A space-separated list of permissions for the query. .PP \fBA least one of the above options must be set in this check.\fR .PP Additional Options: .IP "expect_source = [ ....]" A space-separated list of types and type attributes. Each of these types must be seen as the source of a rule that matches the criteria. At the end of the query, each unseen type in this list will be reported as a failure. This is optional. .IP "expect_target = [ ....]" A space-separated list of types and type attributes. Each of these types must be seen as the target of a rule that matches the criteria. At the end of the query, each unseen type in this list will be reported as a failure. This is optional. .IP "exempt_source = [ ....]" A space-separated list of types and type attributes. Rules with these as the source will be ignored. This is optional. .IP "exempt_target = [ ....]" A space-separated list of types and type attributes. Rules with these as the target will be ignored. This is optional. .PP \fBNote:\fR If a rule has an attribute source, all of the member types must be in the expect_source list or exempt_source list to pass. Similarly, if a rule has an attribute target, all of the member types must be in the expect_target list or exempt_target list to pass. .SH "ROLE BASED ACCESS CONTROL ALLOW RULE ASSERTION" This checks for the nonexistence of role based access control (RBAC) allow rules. The check_type is \fBassert_rbac\fR. It will run the query and any unexpected results from the query, removing any exempted sources or targets, will be listed as failures. Any expected results that are not seen will also be listed as failures. .PP Criteria options: .IP "source = " The target role criteria for the query. .PP \fBA least one of the above options must be set in this check.\fR .PP Additional Options: .IP "expect_source = [ ....]" A space-separated list of roles. Each of these roles must be seen as the source of a rule that matches the criteria. At the end of the query, each unseen role in this list will be reported as a failure. This is optional. .IP "expect_target = [ ....]" A space-separated list of roles. Each of these roles must be seen as the target of a rule that matches the criteria. At the end of the query, each unseen role in this list will be reported as a failure. This is optional. .IP "exempt_source = [ ....]" A space-separated list of roles. Rules with these as the source will be ignored. This is optional. .IP "exempt_target = [ ....]" A space-separated list of roles. Rules with these as the target will be ignored. This is optional. .SH "EMPTY TYPE ATTRIBUTE ASSERTION" This checks that the specified attribute is empty. This can optionally be set to also pass if the attribute does not exist. The check_type is \fBempty_typeattr\fR. .PP Options: .IP "attr = " The type attribute to check. This is required. .IP "missing_ok = " Consider the check passing if the attribute does not exist. This is optional. Default is false. .SH "READ-ONLY EXECUTABLES ASSERTION" This checks that all file types that are executable are read-only. The check_type is \fBro_execs\fR. .PP Options: .IP "exempt_file = [ ....]" A space-separated list of types and type attributes. These will not be considered executable. This is optional. .IP "exempt_exec_domain = [ ....]" A space-separated list of types and type attributes. Rules with these as the source will be ignored if they allow file execute permission. This is optional. .IP "exempt_write_domain = [ ....]" A space-separated list of types and type attributes. Rules with these as the source will be ignored if they allow file write or append permissions on types determined executable. This is optional. .SH "CONFIGURATION EXAMPLES" .PP \fBExample\ \&1.\ \&A check called "no_unconfined" that will determine if the domain_unconfined_type attribute is empty or missing.\fR .sp .if n \{\ .RS 4 .\} .nf [no_unconfined] check_type = empty_typeattr desc = Verify that the domain_unconfined_type attribute is missing or empty. attr = domain_unconfined_type missing_ok = True .fi .if n \{\ .RE .\} .PP \fBExample\ \&2.\ \&A check called "ro_execs" that will determine if all executable types are read-only.\fR .sp .if n \{\ .RS 4 .\} .nf [ro_execs] check_type = empty_typeattr desc = Verify that the all executables and libraries are read-only. .fi .if n \{\ .RE .\} .PP \fBExample\ \&3.\ \&A check called "execheap" that will determine that there are no domains with the execheap permission except for unconfined_execheap_t.\fR .sp .if n \{\ .RS 4 .\} .nf [execheap] check_type = assert_te desc = Verify no domains have executable heap. tclass = process perms = execheap exempt_source = unconfined_execheap_t .fi .if n \{\ .RE .\} .PP .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.4.0/man/sediff.1000066400000000000000000000103621402045477700153200ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sediff 1 2016-04-19 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME sediff \- SELinux policy difference tool .SH SYNOPSIS \fBsediff\fR [OPTIONS] [EXPRESSION] POLICY1 POLICY2 .SH DESCRIPTION Determine the differences between two SELinux policies. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If not provided, \fBsediff\fR will print an error message and exit. .SH EXPRESSIONS .P The user may specify an expression listing the policy elements to differentiate. If not provided, all supported policy elements are examined. .SS Component Differences .IP "--common" Find differences in common permission sets. .IP "-c, --class" Find differences in object classes. .IP "-t, --type" Find differences in attributes associated with types. .IP "-a, --attribute" Find differences in types assigned to attributes. .IP "-r, --role" Find differences in types authorized for roles. .IP "-u, --user" Find differences in roles authorized for users. .IP "-b, --bool" Find differences in the default values of booleans. .IP "--sensitivity" Find differences in sensitivity definitions. .IP "--category" Find differences in category definitions. .IP "--level" Find differences in MLS level definitions. .SS Type Enforcement Rule Differences .IP "-A" Find differences in allow and allowxperm rules. .IP "--allow" Find differences in allow rules. .IP "--auditallow" Find differences in auditallow rules. .IP "--dontaudit" Find differences in dontaudit rules. .IP "--neverallow" Find differences in neverallow rules. .IP "--allowxperm" Find differences in allowxperm rules. .IP "--auditallowxperm" Find differences in auditallowxperm rules. .IP "--dontauditxperm" Find differences in dontauditxperm rules. .IP "--neverallowxperm" Find differences in neverallowxperm rules. .IP "-T, --type_trans" Find differences in type_transition rules. .IP "--type_member" Find differences in type_member rules. .IP "--type_change" Find differences in type_change rules. .SS RBAC Rule Differences .IP "--role_allow" Find differences in role allow rules. .IP "--role_trans" Find differences in role_transition rules. .SS MLS Rule Differences .IP "--range_trans" Find differences in range_transition rules. .SS Constraint Differences .IP "--constrain" Find differences in constrain rules. .IP "--mlsconstrain" Find differences in mlsconstrain rules. .IP "--validatetrans" Find differences in validatetrans rules. .IP "--mlsvalidatetrans" Find differences in mlsvalidatetrans rules. .SS Labeling Statement Differences .IP "--initialsid" Find differences in initial SID statements. .IP "--fs_use" Find differences in fs_use_* statements. .IP "--genfscon" Find differences in genfscon statements. .IP "--netifcon" Find differences in netifcon statements. .IP "--nodecon" Find differences in nodecon statements. .IP "--portcon" Find differences in portcon statements. .SS Other Differences .IP "--default" Find differences in default_* statements. .IP "--property" Find differences in policy properties. Only applicable for binary policies (policy version, MLS enabled/disabled, unknown permissions setting). .IP "--polcap" Find differences in policy capabilities. .IP "--typebounds" Find differences in typebound statements. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--stats" Print difference statistics only. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH DIFFERENCES .PP .B sediff categorizes differences in policy elements into one of three forms. .RS .IP "added" The element exists only in the modified policy. .IP "removed" The element exists only in the original policy. .IP "modified" The element exists in both policies but its semantic meaning has changed. For example, a class is modified if one or more permissions are added or removed. .RE .PP .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sedta(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.4.0/man/sedta.1000066400000000000000000000051611402045477700151610ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sedta 1 2016-02-20 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME sedta \- Domain transition analysis for SELinux policies .SH SYNOPSIS \fBsedta\fR [OPTIONS] -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH DESCRIPTION .PP \fBsedta\fR is a command line tool that allows the user to perform domain transition analyses on an SELinux policy. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If no policy file is provided, \fBsedta\fR will search for the policy running on the current system. If no policy can be found, \fBsedta\fR will print an error message and exit. .SH OPTIONS .SS Analysis Settings .IP "-p POLICY" Specify the policy to analyze. If none is specified, \fBsedta\fR will search for the policy running on the current system. .IP "-s SOURCE" Specify the source type to use in the domain transition analysis. .IP "-t TARGET" Specify the target type to use in the domain transition analysis. Using this option will also require specifying an analysis algorithm. .SS Analysis Algorithms \fBsedta\fR uses graph algorithms to analyze the domain transition paths of an SELinux policy. The following algorithms are options for determining paths from a source type to a target type. .IP "-S" Print the shortest domain transition path(s) from the source type to the target type. If multiple paths have the same length, all will be displayed. .IP "-A LIMIT" Print all domain transition path(s) up to LIMIT steps long. Depending on the connectiveness of the policy, this may be extremely expensive. .SS Analysis Options .IP -r Perform a reverse domain transition analysis. The domain transitions will be analyzed to find the the parent domains, instead of finding the child domains. .IP "-l LIMIT_TRANS" Specify the maximum number of domain transitions to output. The default is unlimited. .IP EXCLUDE A space-separated list of types to exclude from the analysis. .SS General Options .IP "--stats" Print domain transition graph statistics at the end of the analysis. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sediff(1), seinfo(1), seinfoflow(1), sesearch(1) setools-4.4.0/man/seinfo.1000066400000000000000000000125611402045477700153460ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfo 1 2016-02-20 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME seinfo \- SELinux policy information tool .SH SYNOPSIS \fBseinfo\fR [OPTIONS] [EXPRESSION] [POLICY] .SH DESCRIPTION \fBseinfo\fR allows the user to query the components of a SELinux policy. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If no policy file is provided, \fBseinfo\fR will search for the policy running on the current system. If no policy can be found, \fBseinfo\fR will print an error message and exit. .SH EXPRESSIONS .P One or more of the following component types can be queried. If no expressions are provided, policy statistics will be printed. .IP "-a [ATTR], --attribute [ATTR]" Print a list of type attributes or, if ATTR is provided, print the named attribute. With \fI-x\fR, print a list of types assigned to each displayed attribute. .IP "-b [BOOL], --bool [BOOL]" Print a list of Booleans or, if BOOL is provided, print the named boolean. With \fI-x\fR, print the statement of each displayed conditional boolean. .IP "-c [CLASS], --class [CLASS]" Print a list of object classes or, if CLASS is provided, print the named object class. With \fI-x\fR, print a list of permissions for each displayed object class. .IP "-r [ROLE], --role [ROLE]" Print a list of roles or, if NAME is provided, print the named role. With \fI-x\fR, print the statement for each displayed role. .IP "-t [TYPE], --type [TYPE]" Print a list of types or, if TYPE is provided, print the named type. With \fI-x\fR, print a list of attributes which include each displayed type. .IP "-u [USER], --user [USER]" Print a list of users or, if USER is provided, print the named user. With \fI-x\fR, print a list of statement for each displayed user. .IP "--category [CAT]" Print a list of categories or, if CAT is provided, print the named category. With \fI-x\fR, print a list of sensitivities with which each displayed category may be associated. .IP "--common [COMMON]" Print a list of common permission sets or, if COMMON is provided, print the named common. With \fI-x\fR, print a list of permissions in the set. .IP "--constrain [CLASS]" Print a list of constraints and MLS constraints statements or, if CLASS is provided, print all constraints for the named object class. There is no expanded information for this component. .IP "--default [CLASS]" Print a list of default_* statements or, if CLASS is provided, print all default_* statements for the named object class. There is no expanded information for this component. .IP "--fs_use [FS_TYPE]" Print a list of fs_use_* statements or, if FS_TYPE is provided, print the statement for the named filesystem type. There is no expanded information for this component. .IP "--genfscon [FS_TYPE]" Print a list of genfscon statements or, if FS_TYPE is provided, print the statement for the named filesystem type. There is no expanded information for this component. .IP "--initialsid [NAME]" Print a list of initial SIDs or, if NAME is provided, print the named initial SID. With \fI-x\fR, print the context assigned to each displayed SID. .IP "--netifcon [DEVICE]" Print a list of netif contexts or, if DEVICE is provided, print the named statement for the interface. There is no expanded information for this component. .IP "--nodecon [ADDR]" Print a list of node contexts or, if ADDR is provided, print the named statement for the node with address. There is no expanded information for this component. .IP "--permissive [TYPE]" Print permissive types or, if TYPE is specified, print the named statement if it is permissive. There is no expanded information for this component. .IP "--polcap [NAME]" Print policy capabilities or, if NAME is specified, print the named capability, if enabled. With \fI-x\fR, print the statement. .IP "--portcon [PORTNUM[-PORTNUM]]" Print a list of port contexts or, if PORT or PORT range is provided, print the named statement for the port/port range. There is no expanded information for this component. .IP "--sensitivity [SENS]" Print a list of sensitivities or, if SENS is provided, print the named sensitivity. With \fI-x\fR, print the statement for each sensitivity. .IP "--typebounds [BOUND_TYPE]" Print a list of typebounds statements or, if BOUND_TYPE is provided, print the statement for the named bound type. There is no expanded information for this component. .IP "--validatetrans [CLASS]" Print a list of validatetrans and MLS validatetrans rules or, if CLASS is provided, print all constraints for the named object class. There is no expanded information for this component. .IP "--all" Print all components. .SH OPTIONS .IP "-x, --expand" Print additional details for each component matching the expression. See the description of each component for the details this option will provide. .IP "--flat" Exclude headers and indentation in output. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfoflow(1), sesearch(1) setools-4.4.0/man/seinfoflow.1000066400000000000000000000053211402045477700162320ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH seinfoflow 1 2016-02-20 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME seinfoflow \- Information flow analysis for SELinux policies .SH SYNOPSIS \fBseinfoflow\fR [OPTIONS] -m MAP -s SOURCE [-t TARGET (-S|-A LIMIT)] [EXCLUDE [EXCLUDE ...]] .SH DESCRIPTION .PP \fBseinfoflow\fR is a command line tool that allows the user to perform information flow analyses on an SELinux policy. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If no policy file is provided, \fBseinfoflow\fR will search for the policy running on the current system. If no policy can be found, \fBseinfoflow\fR will print an error message and exit. .SH OPTIONS .SS Analysis Settings .IP "-p POLICY" Specify the policy to analyze. If none is specified, \fBseinfoflow\fR will search for the policy running on the current system. .IP "-m MAP" Specify the path to the permission map file to use in the information flow analysis. .IP "-s SOURCE" Specify the source type to use in the information flow analysis. .IP "-t TARGET" Specify the target type to use in the information flow analysis. Using this option will also require specifying an analysis algorithm. .SS Analysis Algorithms \fBseinfoflow\fR uses graph algorithms to analyze the information flow paths of an SELinux policy. The following algorithms are options for determining paths from a source type to a target type. .IP "-S" Print the shortest information flow path(s) from the source type to the target type. If multiple paths have the same length, all will be displayed. .IP "-A LIMIT" Print all information flow path(s) up to LIMIT steps long. Depending on the connectiveness of the policy, a limit of 5 or more may be extremely expensive. .SS Analysis Options .IP "-w MIN_WEIGHT" Specify the minimum permission weight to consider for the analysis (1-10). The default is 3. .IP "-l LIMIT_FLOWS" Specify the maximum number of information flows to output. The default is unlimited. .IP EXCLUDE A space-separated list of types to exclude from the analysis. .SS General Options .IP "--stats" Print information flow graph statistics at the end of the analysis. .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfo(1), sesearch(1) setools-4.4.0/man/sesearch.1000066400000000000000000000074221402045477700156600ustar00rootroot00000000000000.\" Copyright (c) 2016 Tresys Technology, LLC. All rights reserved. .TH sesearch 1 2016-02-20 "SELinux Project" "SETools: SELinux Policy Analysis Tools" .SH NAME sesearch \- SELinux policy query tool .SH SYNOPSIS \fBsesearch\fR [OPTIONS] [OPTIONS] [EXPRESSION] [POLICY] .SH DESCRIPTION \fBsesearch\fR allows the user to search the rules in a SELinux policy. .SH POLICY .PP A single file containing a binary policy. This file is usually named by version on Linux systems, for example, \fIpolicy.30\fR. This file is usually named \fIsepolicy\fR on Android systems. If no policy file is provided, \fBsesearch\fR will search for the policy running on the current system. If no policy can be found, \fBsesearch\fR will print an error message and exit. .SH EXPRESSIONS The user may specify an expression containing values for a given field(s) in a rule. If no expression is specified or if none of the specified fields apply to a given rule type, all rules of that type are considered to match the expression. .SS Type Enforcement Rule Types .IP "-A" Find allow and allowxperm rules. .IP "--allow" Find allow rules. .IP "--auditallow" Find auditallow rules. .IP "--dontaudit" Find dontaudit rules. .IP "--neverallow" Find neverallow rules. .IP "--allowxperm" Find allowxperm rules. .IP "--auditallowxperm" Find auditallowxperm rules. .IP "--dontauditxperm" Find dontauditxperm rules. .IP "--neverallowxperm" Find neverallowxperm rules. .IP "-T, --type_trans" Find type_transition rules. .IP "--type_member" Find type_member rules. .IP "--type_change" Find type_change rules. .SS RBAC Rule Types .IP "--role_allow" Find role allow rules. .IP "--role_trans" Find role_transition rules. .SS MLS Rule Types .IP "--range_trans" Find range_transition rules. .SS Rule Fields .IP "-s NAME, --source NAME" Find rules with NAME as their source type/role. .IP "-t NAME, --target NAME" Find rules with NAME as their target type/role. .IP "-D NAME, --default NAME" Find rules with NAME as their default type/role/level. .IP "-c NAME, --class NAME" Find rules with NAME as their object class. .IP "-p P1[,P2,...] --perm P1[,P2...]" Find rules with at least one of the specified permissions. Multiple permissions may be specified as a comma-separated list. .IP "-b BOOL[,B2,...], --bool BOOL[,B2,...]" Find conditional rules with the named Boolean in their conditional expression. Multiple Booleans may be specified as a comma-separated list. This option will include rules in both the true and false lists of the conditional. .SS Search Options The following additional options modify how the search is performed. .IP "-ds" A matching rule must have the specified source attribute/type/role explicitly, instead of matching by attribute contents. .IP "-dt" A matching rule must have the specified target attribute/type/role explicitly, instead of matching by attribute contents. .IP "-eb" A matching rule must have all specified Booleans, instead of matching any of the specified Boolean. .IP "-ep" A matching rule must have all specified permissions, instead of matching any of the specified permission. .IP "-rs" Use regular expression for matching the source type/role. .IP "-rt" Use regular expression for matching the target type/role. .IP "-rc" Use regular expression for matching the object class. .IP "-rd" Use regular expression for matching the default type/role. .IP "-rb" Use regular expression for matching Booleans. .SH OPTIONS .IP "-h, --help" Print help information and exit. .IP "--version" Print version information and exit. .IP "-v, --verbose" Print additional informational messages. .IP "--debug" Enable debugging output. .SH AUTHOR Chris PeBenito .SH BUGS Please report bugs via the SETools bug tracker, https://github.com/SELinuxProject/setools/issues .SH SEE ALSO apol(1), sediff(1), sedta(1), seinfo(1), seinfoflow(1) setools-4.4.0/patches/000077500000000000000000000000001402045477700146505ustar00rootroot00000000000000setools-4.4.0/patches/README000066400000000000000000000001141402045477700155240ustar00rootroot00000000000000If there is a bug in one of SETools' dependencies, patches can be put here. setools-4.4.0/qhc/000077500000000000000000000000001402045477700137745ustar00rootroot00000000000000setools-4.4.0/qhc/analyses.html000066400000000000000000000004461402045477700165050ustar00rootroot00000000000000 Analyses

Analyses

Apol supports the following analyses:

setools-4.4.0/qhc/apol.qhcp000066400000000000000000000012551402045477700156070ustar00rootroot00000000000000 Apol Help qthelp://com.github.selinuxproject.setools/doc/index.html qthelp://com.github.selinuxproject.setools/doc/index.html apol.qhp apol.qch apol.qch setools-4.4.0/qhc/apol.qhp000066400000000000000000000026161402045477700154460ustar00rootroot00000000000000 com.github.selinuxproject.setools doc apol apol
*.html setools-4.4.0/qhc/components.html000066400000000000000000000007541402045477700170550ustar00rootroot00000000000000 Components

Components

The policy components tabs provide the means to examine, search, and relate the core components of an SELinux policy.

Apol supports querying the following policy components:

  • Booleans
  • Categories
  • Commons
  • Roles
  • Object Classes
  • Sensitivities
  • Types
  • Type Attributes
  • Users
setools-4.4.0/qhc/dta.html000066400000000000000000000140671402045477700154420ustar00rootroot00000000000000 Domain Transition Analysis

Domain Transition Analysis

A key feature of Type Enforcement (TE) security is the ability to define domain types with which programs run, use that domain type to control access to objects (which are also typed), and strictly control the ability of a process to change its domain type. This last ability is known as domain transition.

Apol supports analysis of an SELinux policy to understand the domain transitions it allows. As with all access in SELinux, the ability to transition from one domain to another is controlled by 'allow' rules in the policy. Below, we describe how apol performs a domain transition analysis.

Types Used in Domain Transitions

When discussing domain transition access, there are three different types we must consider:

  • SOURCE TYPE: This is the domain type associated with a process that is trying to change (transition) its domain type to another type.
  • TARGET TYPE: This is the domain type to which the source type is trying to transition.
  • FILE TYPE (ENTRYPOINT TYPE): This is a type associated with an executable file object that allows the target type to be entered as part of an exec() system call.

Domain Transition Criteria

In SELinux, there are two ways for a domain transition to occur, on exec(), and on setcon(). The common case is for a domain transition to occur on exec().

Transitions on Exec()

In SELinux, four types of access (and hence at four rules) must be allowed by the policy for a domain transition to occur. These access types form the criteria used by apol to determine allowed transitions.

The criteria for an allowed domain transition are as follows. In the examples below, assume user_t is the source type, passwd_t is the target type, and passwd_exec_t is the file entry point type.

  1. A rule must exist that allows the SOURCE domain type transition access for process object class for the TARGET domain type. For example, the rule:
    
        allow user_t passwd_t : process transition;
    
    
    meets this criterion by allowing the source type (user_t) process: transition permission to the target type (passwd_t).
  2. A rule must exist that allows the SOURCE domain type execute access to the FILE ENTRYPOINT type. For example, the rule:
    
        allow user_t passwd_exec_t : file { read getattr execute };
    
    
    meets the criterion by allowing the source type (user_t) execute access to the file entrypoint type (passwd_exec_t).
  3. A rule must exist that allows the TARGET domain type entrypoint access to the FILE ENTRYPOINT type for file objects. For example, the rule:
    
        allow passwd_t passwd_exec_t : file entrypoint;
    
    
    meets this criterion by allowing the target type (passwd_t) file: entrypoint access to the file entrypoint type (passwd_exec_t).
  4. There must be a way for the transition to be triggered. Typically this is accomplished in the policy with a TYPE TRANSITION statement. For example, the statement:
    
        type_transition user_t password_exec_t : process passwd_t;
    
    
    meets this criterion by specifying that when user_t executes a program with the passwd_exec_t type, the default type of the new process is passwd_t. This is the most common specifier because it does not require the programs to be SELinux-aware. Alternatively, the program can be made SELinux-aware and the program itself may specify the type of the new process. For example, the statement:
    
        allow user_t self : process setexec;
    
    
    allows the source type (user_t) to specify the type of new processes when executing programs. In both the type transition and setexec cases, the types that the source domain may transition to are limited by the previous three criterion.

In the analysis results, apol will list all the types that meet the above four criteria.

Transitions on Setcon()

SELinux also supports domain transitions that are requested by SELinux-aware programs (also known as a dynamic domain transition), using the setcon() libselinux function. Two types of access must be allowed by the policy for a dynamic domain transition to occur. These access types form the criteria used by apol to determine allowed transitions.

The criteria for an allowed dynamic domain transition are as follows. In the examples below, assume souce_t is the source type and, target_t is the target type.

  1. A rule must exist that allows the SOURCE domain type dyntransition access for process object class for the TARGET domain type. For example, the rule:
    
        allow source_t target_t : process transition;
    
    
    meets this criterion by allowing the source type (source_t) process: dyntransition permission to the target type (target_t).
  2. A rule must exist that allows the SOURCE domain type setcurrent access so it can set its current SELinux context. For example, the rule:
    
        allow source_t source_t : process setcurrent;
    
    
    meets the criterion by allowing the source type (source_t) setcurrent access on itself.

In the analysis results, apol will list all the types that meet the above two criteria.

Reverse Transitions

Apol supports both forward and reverse domain transition analysis. A forward analysis determines all the TARGET types to which the selected SOURCE types may transition (find child domains/processes). A reverse analysis is the opposite; select a TARGET type and determine all the SOURCE types that may transition to the target type (find parent domains/processes).

setools-4.4.0/qhc/index.html000066400000000000000000000035561402045477700160020ustar00rootroot00000000000000 Apol

Apol SELinux Policy Analysis

Overview

This file contains basic help information for using apol, a graphical policy analysis tool for Security Enhanced (SELinux) policies. The tool provides the ability to:

  1. Examine, search, and relate policy components (types, type attributes, object classes, object permissions, roles, users, initials SIDs, MLS components, network and file system contexts, and booleans), and policy rules.
  2. Perform some automated analysis of policies, including forward and reverse domain transition analyses, and information flow analysis.

Apol supports source, and binary policies. Certain apol features may be disabled if the underlying policy does not support the action. For example, rule searches will not report line numbers when searching monolithic binary polices.

Apol provides compatibility with the current and previous policy syntax. It supports analysis of policy versions 15 and up.

Menus

Use Open from the File menu to open a valid policy. Only one policy can be open at a time; opening a second policy will result in the first being closed.

The Permission Map menu allows for opening, editing, and saving permission mappings. These are used by apol's information flow analysis.

Starting an Analysis

To begin analyzing a policy, click the new analysis button. A menu of available analysis tools will be presented. Select one, and a new analysis tab will open. Any analysis can be started multiple times, and each will operate independently, so multiple concurrent analyses can be performed. To help manage multiple tabs, the tabs can be renamed by double-click the tab.

setools-4.4.0/qhc/infoflow.html000066400000000000000000000331751402045477700165160ustar00rootroot00000000000000 Information Flow Analysis

Information Flow Analysis

Apol supports the ability to automate the search for overt information flows between two types. The purpose of this analysis is to identify undesirable or unexpected flows of information allowed by a Type Enforcement (TE) policy. For example, imagine that the type shadow_t is assigned to the shadow password file /etc/shadow. To determine all the types to which information can flow from the shadow_t type (e.g, indicating possible paths for encrypted passwords to be unintentionally leaked), do a "flow from" analysis on the shadow_t type. Another example might be a firewall application where the intent is to understand all flows allowed between two network interfaces.

Information flow analysis in SELinux is challenging for several reasons, including:

  • The TE policy mechanism is extremely flexible, allowing for good and bad flows to be easily specified, not necessarily by the policy writer's intent.
  • TE policies tend to be complex, with possibly tens of thousands of rules and hundreds of types, making it difficult for a policy writer to know all that is allowed.
  • SELinux currently supports over 50 object classes and hundreds of object permissions, each of which must be examined with their ability to allow information flow from/to its associated object class.

The remainder of this file provides an overview on how apol performs information flow analysis.

What Is Overt Information Flow In SELinux?

Information flow is defined in terms of access allowed (not necessarily whether that access is actually used). In SELinux, all objects and subjects have an associated type. Generally speaking, subjects can read or write objects, and thereby cause information to flow into and out of objects, and into and out of themselves. For example, given two types (say subject_t and object_t) and a subject (with subject_t type) able to read, but not write, an object (with object_t type), a rule that would allow this access might look like the following:

allow subject_t object_t : {file link_file} read;

This case would have the following direct information flows for the types subject_t and object_t:

        subject_t: FROM object_t

        object_t:  TO subject_t

If this were the only rule relating to these two types, there would be no other direct information flows from or to either.

An information flow can only occur when a subject is involved; a flow directly between two objects cannot exist since a subject is required to cause action. In SELinux, processes are generally the subject. There are dozens of object classes (including processes, which are both subjects and objects).

In apol, the subject is easy to recognize; any type that is used in the 'source' field of an allow rule is presumed to be associated with a subject, usually as the domain type of some process. The object type is the type used in the 'target' field of an allow rule.

In the case of objects, the allow rule also explicitly identifies the object classes for which the rule applies. This fact results in a complication for analyzing information flows; specifically that flows between types are restricted by object classes. A flow between types is typically not allowed for all object classes, but for only those classes identified. So to be more precise, the direct information flows allowed by the object rules for object_t in the example above are:

        object_t [file, link_file]:  TO subject_t

A perspective difference exists between source (subject) types and target (object) types. A read permission between a source type and a target type is a flow out of the target (which is being read) and flow into the source (which, being a process, is receiving the data being read into its memory).

Object permission mappings

The above examples used 'read' permission, but described flows as 'in' or 'out' or 'from' and 'to'. In general, for information flow analysis, the only access between subjects and objects that are of interest, are read and write. Remembering the perspective difference mentioned above, read and write access results in the following flow for subjects (sources) and objects (targets):

        SUBJECT: READ:  IN flow
                 WRITE: OUT flow

        OBJECT:  READ:  OUT flow
                 WRITE: IN flow

NOTE: A process can be either a subject or an object, so when the process object class is specified in the allow rule, the target type is associated with process object class and the object flow rules apply.

Although read and write access are the only access rights of interest for an information flow analysis, 'read' and 'write' permissions are not the only SELinux permissions of interest. The name of a permission does not necessarily imply whether it allows read or write access. Indeed, to perform an information flow analysis requires mapping all defined permissions for all object classes to read and write access.

This mapping can be a difficult chore, and certainly requires extensive understanding of the access allowed by each of the hundreds of permissions currently defined. For example, the file object class has the getattr permission defined that allows the ability to determine information about a file (such as date created and size). One could consider this a read access since the subject is reading information about the file. Then again this begins to feel like COVERT information flow analysis, where one is concerned about illicit signaling of information through non-traditional means (e.g., signaling the critical data by varying the size of file is a covert flow, writing the data directly in the file so it can be read is an overt flow). This type of decision must be made for each defined object permission for each defined object class.

The permission mapping mechanism in apol allows each permission to be mapped to read, write, both or none. In addition, the tool attempts to 'fix' a permission map to fit the needs of the currently opened policy. So, for example, if a permission map file does not map a set of permissions, or skips an entire object class, apol will label the missing permissions to "unmapped" and treat them as if they were mapped to 'none.' Likewise, if a map has permissions that are undefined in the current policy, it will ignore those mappings.

Apol provides mechanisms to manage and customize permission mappings that best suit the analyst's needs. Use the Tools menu (see below) to modify permission mappings.

Permission Weighting

In addition to mapping each permission to read, write, both, or none, it is possible to assign the permission a weight between 1 and 10. Apol uses this weight to rate the importance of the information flow this permission represents and allows the user to make fine-grained distinctions between high-bandwidth, overt information flows and low-bandwidth, or difficult to exploit, covert information flows. For example, the permissions read and write on the file object could be given a weight of 10 because they are very high-bandwidth information flows. Additionally, the use permission on the fd object (file descriptor) would probably be given a weight of 1 as it is a very low-bandwidth covert flow at best. Note that a permission might be important for access control, like fd: use, but be given a low weight for information flow because it cannot be used to pass large amounts of information.

The default permission maps that are installed with apol have weights assigned for all of the permissions. The weights are in four general categories as follows:

  • 1 - 2 difficult to exploit covert flows (example: fd:use)
  • 3 - 5 less difficult to exploit covert flows (example: process:signal)
  • 6 - 7 difficult to use, noisy, or low-bandwidth overt flows (example: file:setattr)
  • 8 - 10 high-bandwidth overt flows (example: file:write)

These categories are loosely defined and the placement of permissions into these categories is subjective. Additional work needs to be done to verify the accuracy of both the mappings of the permissions and the assigned weights.

Types of information flow analysis

The examples so far have only looked at 'direct' information flows. As its name implies, direct information flow analysis examines a policy for information flows that are directly permitted by one or more allow rules. In essence, every allow rule defines a direct information flow between the source and target types (for those allowed permissions that map to read, write, or both). The direct information flow analysis automates the search for these direct flows.

Transitive information flow analysis attempts to link together a series of direct information flows to find an indirect path in which information can flow between two types. The results for a transitive closure will show one or more steps in the chain required for information to flow between the start and end types. Currently, the results will only show one such path for each end type; specifically the shortest path.

For example, given the following rules:

        allow one_t two_t : file write;
        allow three_t two_t: file read;

A direct flow analysis between one_t and three_t would not show any flows since no rule explicitly allows access between them. However, a two-step flow exists that would allow flow between these two types, namely one_t writing information into a file type (two_t) that three_t can read. These are the types of flows that the transitive analysis attempts to find.

For direct analyses, the results are presented in tree form in the browser tab. Each node in the tree represents a flow (in the direction selected) between the type of the parent node and the type of the node. The results window shows each step of the flow including the contributing access rule(s).

Managing Permission Mappings

The ability to directly manage permission maps is important for the following reasons:

  • Permission maps are central to analyzing information flows, and the correctness of the map has a direct influence on the value of he results.
  • The mapping for individual permissions and object classes are subjective, and changing permissions to alter the analysis might be necessary (e.g., by unmapping certain object classes to remove them from the analysis).
  • The analyst may be working with several different policies each with different definitions of object classes and permissions.

Because of these reasons, apol was designed to provide great latitude in managing permission mappings using Permission Map menu. A user need not manage permission maps directly; apol is installed with default permission maps (typically in /usr/share/setools/perm_map) that will be loaded automatically when an information flow analysis is performed.

Use the Permission Map menu to manually load a permission map from an arbitrary file. This capability allows the user to keep several versions of permission map files, loading the correct one for a given analysis.

Although the user could view and modify mappings by editing a map file directly, an easier (and less error-prone) approach is apol's perm map viewer. Select Edit Permission Mapfrom the Permission Map menu to display all object classes and permissions currently mapped (or unmapped) in the currently loaded policy. In addition, each permission's weight value is shown. These values tell apol the importance of each permission to the analysis. The user can configure these weight values according to the analysis goals. For example, the user may consider any read or write permissions of highest importance to the analysis, whereas permission to use a file descriptor may be of least importance. A permission will default to a weight of 1 if a weight value is not provided for the permission in the permission map.

Finding more flows

For a transitive information flow, there might be many different information flows between two types. For example, given the following policy:

        allow one_t two_t : file write;
        allow three_t two_t: file read;
        allow four_t two_t: file read;
        allow four_t three_t: file write;

In this policy, two ways exist that information can flow between one_t and three_t: through three_t and through three_t and four_t. In complicated policies, many information flows between two types can exist. The analysis algorithm can find all information flows, but this would be time prohibitive on large policies. Apol provides two ways of constraining the analysis time. Two analysis algorithms are provided:

  1. Shortest Paths: The shortest path between the source and target type will be found. If there are multiple shortest paths, all with be found.
  2. All Paths: All paths between the source and target type will be found. To constrain this, an upper limit of path length must be specified. For typical policies, a path length more than 4 or 5 may be very expensive.

Additionally, the analysis can be constrained by number of results. The Limit Results option will stop the analysis if the specified number of results is reached. There is no idication if there are more results

setools-4.4.0/qhc/labeling.html000066400000000000000000000005571402045477700164460ustar00rootroot00000000000000 Labeling

Labeling

Apol supports querying the following labeling statements:

  • Fs_use_* Statements
  • Genfscon Statements
  • Initial SID Statements
  • Netifcon Statements
  • Nodecon Statements
  • Portcon Statements
setools-4.4.0/qhc/rules.html000066400000000000000000000004631402045477700160170ustar00rootroot00000000000000 Rules

Rules

Apol supports querying the following rule types:

  • Constraints
  • Multi-level Security (MLS)
  • Role-based Access Control (RBAC)
  • Type Enforcement (TE)
setools-4.4.0/sechecker000077500000000000000000000044121402045477700151040ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2020 Microsoft Corporation # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import setools import argparse import sys import logging import signal signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser(description="SELinux policy checker tool.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("config", help="Path to the checker configuration file.") parser.add_argument("policy", help="Path to the SELinux policy to check.", nargs="?") parser.add_argument("-o", "--output_file", help="Path to log output.", required=False) parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) c = setools.PolicyChecker(p, args.config) if args.output_file: with open(args.output_file, "w") as fd: failures = c.run(output=fd) else: failures = c.run() sys.exit(1 if failures else 0) except setools.exception.InvalidCheckerConfig as err: if args.debug: raise else: print(err) sys.exit(2) except Exception as err: if args.debug: raise else: print(err) sys.exit(3) setools-4.4.0/sediff000077500000000000000000002336221402045477700144170ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import setools import argparse import sys import logging import signal from itertools import chain from contextlib import suppress from typing import List signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser( description="SELinux policy semantic difference tool.", epilog="If no differences are selected, all differences will be printed.") parser.add_argument("POLICY1", help="Path to the first SELinux policy to diff.", nargs=1) parser.add_argument("POLICY2", help="Path to the second SELinux policy to diff.", nargs=1) parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("--stats", action="store_true", help="Display only statistics.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") comp = parser.add_argument_group("component differences") comp.add_argument("--common", action="store_true", help="Print common differences") comp.add_argument("-c", "--class", action="store_true", help="Print class differences", dest="class_") comp.add_argument("-t", "--type", action="store_true", help="Print type differences", dest="type_") comp.add_argument("-a", "--attribute", action="store_true", help="Print type attribute differences") comp.add_argument("-r", "--role", action="store_true", help="Print role differences") comp.add_argument("-u", "--user", action="store_true", help="Print user differences") comp.add_argument("-b", "--bool", action="store_true", help="Print Boolean differences", dest="bool_") comp.add_argument("--sensitivity", action="store_true", help="Print MLS sensitivity differences") comp.add_argument("--category", action="store_true", help="Print MLS category differences") comp.add_argument("--level", action="store_true", help="Print MLS level definition differences") terule = parser.add_argument_group("type enforcement rule differences") terule.add_argument("-A", action="store_true", help="Print allow and allowxperm rule differences") terule.add_argument("--allow", action="store_true", help="Print allow rule differences") terule.add_argument("--neverallow", action="store_true", help="Print neverallow rule differences") terule.add_argument("--auditallow", action="store_true", help="Print auditallow rule differences") terule.add_argument("--dontaudit", action="store_true", help="Print dontaudit rule differences") terule.add_argument("--allowxperm", action="store_true", help="Print allowxperm rule differences") terule.add_argument("--neverallowxperm", action="store_true", help="Print neverallowxperm rule differences") terule.add_argument("--auditallowxperm", action="store_true", help="Print auditallowxperm rule differences") terule.add_argument("--dontauditxperm", action="store_true", help="Print dontauditxperm rule differences") terule.add_argument("-T", "--type_trans", action="store_true", help="Print type_transition rule differences") terule.add_argument("--type_change", action="store_true", help="Print type_change rule differences") terule.add_argument("--type_member", action="store_true", help="Print type_member rule differences") rbacrule = parser.add_argument_group("RBAC rule differences") rbacrule.add_argument("--role_allow", action="store_true", help="Print role allow rule differences") rbacrule.add_argument("--role_trans", action="store_true", help="Print role_transition rule differences") mlsrule = parser.add_argument_group("MLS rule differences") mlsrule.add_argument("--range_trans", action="store_true", help="Print range_transition rule differences") constrain = parser.add_argument_group("Constraint differences") constrain.add_argument("--constrain", action="store_true", help="Print constrain differences") constrain.add_argument("--mlsconstrain", action="store_true", help="Print mlsconstrain differences") constrain.add_argument("--validatetrans", action="store_true", help="Print validatetrans differences") constrain.add_argument("--mlsvalidatetrans", action="store_true", help="Print mlsvalidatetrans differences") labeling = parser.add_argument_group("labeling statement differences") labeling.add_argument("--ibendportcon", action="store_true", help="Print ibendportcon differences") labeling.add_argument("--ibpkeycon", action="store_true", help="Print ibkeycon differences") labeling.add_argument("--initialsid", action="store_true", help="Print initial SID differences") labeling.add_argument("--fs_use", action="store_true", help="Print fs_use_* differences") labeling.add_argument("--genfscon", action="store_true", help="Print genfscon differences") labeling.add_argument("--netifcon", action="store_true", help="Print netifcon differences") labeling.add_argument("--nodecon", action="store_true", help="Print nodecon differences") labeling.add_argument("--portcon", action="store_true", help="Print portcon differences") other = parser.add_argument_group("other differences") other.add_argument("--default", action="store_true", help="Print default_* differences") other.add_argument("--property", action="store_true", help="Print policy property differences (handle_unknown, version, MLS)") other.add_argument("--polcap", action="store_true", help="Print policy capability differences") other.add_argument("--typebounds", action="store_true", help="Print typebounds differences") args = parser.parse_args() if args.A: args.allow = True args.allowxperm = True all_differences = not any((args.class_, args.common, args.type_, args.attribute, args.role, args.user, args.bool_, args.sensitivity, args.category, args.level, args.allow, args.neverallow, args.auditallow, args.dontaudit, args.type_trans, args.type_change, args.type_member, args.role_allow, args.role_trans, args.range_trans, args.initialsid, args.genfscon, args.netifcon, args.nodecon, args.portcon, args.fs_use, args.polcap, args.property, args.default, args.constrain, args.mlsconstrain, args.validatetrans, args.mlsvalidatetrans, args.typebounds, args.allowxperm, args.neverallowxperm, args.auditallowxperm, args.dontauditxperm, args.ibendportcon, args.ibpkeycon)) if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p1 = setools.SELinuxPolicy(args.POLICY1[0]) p2 = setools.SELinuxPolicy(args.POLICY2[0]) diff = setools.PolicyDifference(p1, p2) perms: List[str] if all_differences or args.property: if diff.modified_properties or args.property: print("Policy Properties ({0} Modified)".format(len(diff.modified_properties))) if not args.stats: for name, added, removed in sorted(diff.modified_properties, key=lambda x: x.property): print(" * {0} +{1} -{2}".format(name, added, removed)) print() del diff.modified_properties if all_differences or args.common: if diff.added_commons or diff.removed_commons or diff.modified_commons or args.common: print("Commons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_commons), len(diff.removed_commons), len(diff.modified_commons))) if diff.added_commons and not args.stats: print(" Added Commons: {0}".format(len(diff.added_commons))) for c in sorted(diff.added_commons): print(" + {0}".format(c)) if diff.removed_commons and not args.stats: print(" Removed Commons: {0}".format(len(diff.removed_commons))) for c in sorted(diff.removed_commons): print(" - {0}".format(c)) if diff.modified_commons and not args.stats: print(" Modified Commons: {0}".format(len(diff.modified_commons))) for name, mod in sorted(diff.modified_commons.items()): change = [] if mod.added_perms: change.append("{0} Added permissions".format(len(mod.added_perms))) if mod.removed_perms: change.append("{0} Removed permissions".format(len(mod.removed_perms))) print(" * {0} ({1})".format(name, ", ".join(change))) for p in sorted(mod.added_perms): print(" + {0}".format(p)) for p in sorted(mod.removed_perms): print(" - {0}".format(p)) print() del diff.added_commons del diff.removed_commons del diff.modified_commons if all_differences or args.class_: if diff.added_classes or diff.removed_classes or diff.modified_classes or args.class_: print("Classes ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_classes), len(diff.removed_classes), len(diff.modified_classes))) if diff.added_classes and not args.stats: print(" Added Classes: {0}".format(len(diff.added_classes))) for c in sorted(diff.added_classes): print(" + {0}".format(c)) if diff.removed_classes and not args.stats: print(" Removed Classes: {0}".format(len(diff.removed_classes))) for c in sorted(diff.removed_classes): print(" - {0}".format(c)) if diff.modified_classes and not args.stats: print(" Modified Classes: {0}".format(len(diff.modified_classes))) for name, mod in sorted(diff.modified_classes.items()): change = [] if mod.added_perms: change.append("{0} Added permissions".format(len(mod.added_perms))) if mod.removed_perms: change.append("{0} Removed permissions".format(len(mod.removed_perms))) print(" * {0} ({1})".format(name, ", ".join(change))) for p in sorted(mod.added_perms): print(" + {0}".format(p)) for p in sorted(mod.removed_perms): print(" - {0}".format(p)) print() del diff.added_classes del diff.removed_classes del diff.modified_classes if all_differences or args.bool_: if diff.added_booleans or diff.removed_booleans or \ diff.modified_booleans or args.bool_: print("Booleans ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_booleans), len(diff.removed_booleans), len(diff.modified_booleans))) if diff.added_booleans and not args.stats: print(" Added Booleans: {0}".format(len(diff.added_booleans))) for a in sorted(diff.added_booleans): print(" + {0}".format(a)) if diff.removed_booleans and not args.stats: print(" Removed Booleans: {0}".format(len(diff.removed_booleans))) for a in sorted(diff.removed_booleans): print(" - {0}".format(a)) if diff.modified_booleans and not args.stats: print(" Modified Booleans: {0}".format(len(diff.modified_booleans))) for name, mod in sorted(diff.modified_booleans.items()): print(" * {0} (Modified default state)".format(name)) print(" + {0}".format(mod.added_state)) print(" - {0}".format(mod.removed_state)) print() del diff.added_booleans del diff.removed_booleans del diff.modified_booleans if all_differences or args.role: if diff.added_roles or diff.removed_roles or diff.modified_roles or args.role: print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles), len(diff.removed_roles), len(diff.modified_roles))) if diff.added_roles and not args.stats: print(" Added Roles: {0}".format(len(diff.added_roles))) for r in sorted(diff.added_roles): print(" + {0}".format(r)) if diff.removed_roles and not args.stats: print(" Removed Roles: {0}".format(len(diff.removed_roles))) for r in sorted(diff.removed_roles): print(" - {0}".format(r)) if diff.modified_roles and not args.stats: print(" Modified Roles: {0}".format(len(diff.modified_roles))) for name, mod in sorted(diff.modified_roles.items()): change = [] if mod.added_types: change.append("{0} Added types".format(len(mod.added_types))) if mod.removed_types: change.append("{0} Removed types".format(len(mod.removed_types))) print(" * {0} ({1})".format(name, ", ".join(change))) for t in sorted(mod.added_types): print(" + {0}".format(t)) for t in sorted(mod.removed_types): print(" - {0}".format(t)) print() del diff.added_roles del diff.removed_roles del diff.modified_roles if all_differences or args.type_: if diff.added_types or diff.removed_types or diff.modified_types or args.type_: print("Types ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_types), len(diff.removed_types), len(diff.modified_types))) if diff.added_types and not args.stats: print(" Added Types: {0}".format(len(diff.added_types))) for r in sorted(diff.added_types): print(" + {0}".format(r)) if diff.removed_types and not args.stats: print(" Removed Types: {0}".format(len(diff.removed_types))) for r in sorted(diff.removed_types): print(" - {0}".format(r)) if diff.modified_types and not args.stats: print(" Modified Types: {0}".format(len(diff.modified_types))) for name, mod in sorted(diff.modified_types.items()): change = [] if mod.added_attributes: change.append("{0} Added attributes".format(len(mod.added_attributes))) if mod.removed_attributes: change.append("{0} Removed attributes".format(len(mod.removed_attributes))) if mod.added_aliases: change.append("{0} Added aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed aliases".format(len(mod.removed_aliases))) if mod.modified_permissive: if mod.permissive: change.append("Removed permissive") else: change.append("Added permissive") print(" * {0} ({1})".format(name, ", ".join(change))) if mod.added_attributes or mod.removed_attributes: print(" Attributes:") for t in sorted(mod.added_attributes): print(" + {0}".format(t)) for t in sorted(mod.removed_attributes): print(" - {0}".format(t)) if mod.added_aliases or mod.removed_aliases: print(" Aliases:") for t in sorted(mod.added_aliases): print(" + {0}".format(t)) for t in sorted(mod.removed_aliases): print(" - {0}".format(t)) print() del diff.added_types del diff.removed_types del diff.modified_types if all_differences or args.attribute: if diff.added_type_attributes or diff.removed_type_attributes or \ diff.modified_type_attributes or args.attribute: print("Type Attributes ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_attributes), len(diff.removed_type_attributes), len(diff.modified_type_attributes))) if diff.added_type_attributes and not args.stats: print(" Added Type Attributes: {0}".format(len(diff.added_type_attributes))) for a in sorted(diff.added_type_attributes): print(" + {0}".format(a)) if diff.removed_type_attributes and not args.stats: print(" Removed Type Attributes: {0}".format(len(diff.removed_type_attributes))) for a in sorted(diff.removed_type_attributes): print(" - {0}".format(a)) if diff.modified_type_attributes and not args.stats: print(" Modified Type Attributes: {0}".format(len(diff.modified_type_attributes))) for name, mod in sorted(diff.modified_type_attributes.items()): change = [] if mod.added_types: change.append("{0} Added types".format(len(mod.added_types))) if mod.removed_types: change.append("{0} Removed types".format(len(mod.removed_types))) print(" * {0} ({1})".format(name, ", ".join(change))) for t in sorted(mod.added_types): print(" + {0}".format(t)) for t in sorted(mod.removed_types): print(" - {0}".format(t)) print() del diff.added_type_attributes del diff.removed_type_attributes del diff.modified_type_attributes if all_differences or args.user: if diff.added_users or diff.removed_users or diff.modified_users or args.user: print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users), len(diff.removed_users), len(diff.modified_users))) if diff.added_users and not args.stats: print(" Added Users: {0}".format(len(diff.added_users))) for u in sorted(diff.added_users): print(" + {0}".format(u)) if diff.removed_users and not args.stats: print(" Removed Users: {0}".format(len(diff.removed_users))) for u in sorted(diff.removed_users): print(" - {0}".format(u)) if diff.modified_users and not args.stats: print(" Modified Users: {0}".format(len(diff.modified_users))) for name, mod in sorted(diff.modified_users.items()): change = [] if mod.added_roles: change.append("{0} Added roles".format(len(mod.added_roles))) if mod.removed_roles: change.append("{0} Removed roles".format(len(mod.removed_roles))) if mod.removed_level: change.append("Modified default level") if mod.removed_range: change.append("Modified range") print(" * {0} ({1})".format(name, ", ".join(change))) if mod.added_roles or mod.removed_roles: print(" Roles:") for t in sorted(mod.added_roles): print(" + {0}".format(t)) for t in sorted(mod.removed_roles): print(" - {0}".format(t)) if mod.removed_level: print(" Default level:") print(" + {0}".format(mod.added_level)) print(" - {0}".format(mod.removed_level)) if mod.removed_range: print(" Range:") print(" + {0}".format(mod.added_range)) print(" - {0}".format(mod.removed_range)) print() del diff.added_users del diff.removed_users del diff.modified_users if all_differences or args.category: if diff.added_categories or diff.removed_categories or diff.modified_categories \ or args.category: print("Categories ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_categories), len(diff.removed_categories), len(diff.modified_categories))) if diff.added_categories and not args.stats: print(" Added Categories: {0}".format(len(diff.added_categories))) for c in sorted(diff.added_categories): print(" + {0}".format(c)) if diff.removed_categories and not args.stats: print(" Removed Categories: {0}".format(len(diff.removed_categories))) for c in sorted(diff.removed_categories): print(" - {0}".format(c)) if diff.modified_categories and not args.stats: print(" Modified Categories: {0}".format(len(diff.modified_categories))) for name, mod in sorted(diff.modified_categories.items()): change = [] if mod.added_aliases: change.append("{0} Added Aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) print(" * {0} ({1})".format(name, ", ".join(change))) print(" Aliases:") for a in sorted(mod.added_aliases): print(" + {0}".format(a)) for a in sorted(mod.removed_aliases): print(" - {0}".format(a)) print() del diff.added_categories del diff.removed_categories del diff.modified_categories if all_differences or args.sensitivity: if diff.added_sensitivities or diff.removed_sensitivities or diff.modified_sensitivities \ or args.sensitivity: print("Sensitivities ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_sensitivities), len(diff.removed_sensitivities), len(diff.modified_sensitivities))) if diff.added_sensitivities and not args.stats: print(" Added Sensitivites: {0}".format(len(diff.added_sensitivities))) for s in sorted(diff.added_sensitivities): print(" + {0}".format(s)) if diff.removed_sensitivities and not args.stats: print(" Removed Sensitivities: {0}".format(len(diff.removed_sensitivities))) for s in sorted(diff.removed_sensitivities): print(" - {0}".format(s)) if diff.modified_sensitivities and not args.stats: print(" Modified Sensitivities: {0}".format(len(diff.modified_sensitivities))) for name, mod in sorted(diff.modified_sensitivities.items()): change = [] if mod.added_aliases: change.append("{0} Added Aliases".format(len(mod.added_aliases))) if mod.removed_aliases: change.append("{0} Removed Aliases".format(len(mod.removed_aliases))) print(" * {0} ({1})".format(name, ", ".join(change))) print(" Aliases:") for a in sorted(mod.added_aliases): print(" + {0}".format(a)) for a in sorted(mod.removed_aliases): print(" - {0}".format(a)) print() del diff.added_sensitivities del diff.removed_sensitivities del diff.modified_sensitivities if all_differences or args.level: if diff.added_levels or diff.removed_levels or \ diff.modified_levels or args.level: print("Levels ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_levels), len(diff.removed_levels), len(diff.modified_levels))) if diff.added_levels and not args.stats: print(" Added Levels: {0}".format(len(diff.added_levels))) for a in sorted(diff.added_levels): print(" + {0}".format(a)) if diff.removed_levels and not args.stats: print(" Removed Levels: {0}".format(len(diff.removed_levels))) for r in sorted(diff.removed_levels): print(" - {0}".format(r)) if diff.modified_levels and not args.stats: print(" Modified Levels: {0}".format(len(diff.modified_levels))) for level, added_categories, removed_categories, _ in sorted(diff.modified_levels, key=lambda x: x.level): change = [] if added_categories: change.append("{0} Added Categories".format(len(added_categories))) if removed_categories: change.append("{0} Removed Categories".format(len(removed_categories))) print(" * {0} ({1})".format(level.sensitivity, ", ".join(change))) for c in sorted(added_categories): print(" + {0}".format(c)) for c in sorted(removed_categories): print(" - {0}".format(c)) print() del diff.added_levels del diff.removed_levels del diff.modified_levels if all_differences or args.allow: if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow: print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_allows), len(diff.removed_allows), len(diff.modified_allows))) if diff.added_allows and not args.stats: print(" Added Allow Rules: {0}".format(len(diff.added_allows))) for r in sorted(diff.added_allows): print(" + {0}".format(r)) if diff.removed_allows and not args.stats: print(" Removed Allow Rules: {0}".format(len(diff.removed_allows))) for r in sorted(diff.removed_allows): print(" - {0}".format(r)) if diff.modified_allows and not args.stats: print(" Modified Allow Rules: {0}".format(len(diff.modified_allows))) for rule, added_perms, removed_perms, matched_perms in sorted(diff.modified_allows, key=lambda x: x.rule): perm_str = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perm_str) with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_allows del diff.removed_allows del diff.modified_allows if all_differences or args.allowxperm: if diff.added_allowxperms or diff.removed_allowxperms or diff.modified_allowxperms \ or args.allowxperm: print("Allowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_allowxperms), len(diff.removed_allowxperms), len(diff.modified_allowxperms))) if diff.added_allowxperms and not args.stats: print(" Added Allowxperm Rules: {0}".format(len(diff.added_allowxperms))) for r in sorted(diff.added_allowxperms): print(" + {0}".format(r)) if diff.removed_allowxperms and not args.stats: print(" Removed Allowxperm Rules: {0}".format(len(diff.removed_allowxperms))) for r in sorted(diff.removed_allowxperms): print(" - {0}".format(r)) if diff.modified_allowxperms and not args.stats: print(" Modified Allowxperm Rules: {0}".format(len(diff.modified_allowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_allowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_allowxperms del diff.removed_allowxperms del diff.modified_allowxperms if all_differences or args.neverallow: if diff.added_neverallows or diff.removed_neverallows or diff.modified_neverallows or \ args.neverallow: print("Neverallow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_neverallows), len(diff.removed_neverallows), len(diff.modified_neverallows))) if diff.added_neverallows and not args.stats: print(" Added Neverallow Rules: {0}".format(len(diff.added_neverallows))) for r in sorted(diff.added_neverallows): print(" + {0}".format(r)) if diff.removed_neverallows and not args.stats: print(" Removed Neverallow Rules: {0}".format(len(diff.removed_neverallows))) for r in sorted(diff.removed_neverallows): print(" - {0}".format(r)) if diff.modified_neverallows and not args.stats: print(" Modified Neverallow Rules: {0}".format(len(diff.modified_neverallows))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_neverallows, key=lambda x: x.rule): perm_str = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perm_str) with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_neverallows del diff.removed_neverallows del diff.modified_neverallows if all_differences or args.neverallowxperm: if diff.added_neverallowxperms or diff.removed_neverallowxperms or \ diff.modified_neverallowxperms or args.neverallowxperm: print("Neverallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_neverallowxperms), len(diff.removed_neverallowxperms), len(diff.modified_neverallowxperms))) if diff.added_neverallowxperms and not args.stats: print(" Added Neverallowxperm Rules: {0}".format( len(diff.added_neverallowxperms))) for r in sorted(diff.added_neverallowxperms): print(" + {0}".format(r)) if diff.removed_neverallowxperms and not args.stats: print(" Removed Neverallowxperm Rules: {0}".format( len(diff.removed_neverallowxperms))) for r in sorted(diff.removed_neverallowxperms): print(" - {0}".format(r)) if diff.modified_neverallowxperms and not args.stats: print(" Modified Neverallowxperm Rules: {0}".format( len(diff.modified_neverallowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_neverallowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_neverallowxperms del diff.removed_neverallowxperms del diff.modified_neverallowxperms if all_differences or args.auditallow: if diff.added_auditallows or diff.removed_auditallows or diff.modified_auditallows or \ args.auditallow: print("Auditallow Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_auditallows), len(diff.removed_auditallows), len(diff.modified_auditallows))) if diff.added_auditallows and not args.stats: print(" Added Auditallow Rules: {0}".format(len(diff.added_auditallows))) for r in sorted(diff.added_auditallows): print(" + {0}".format(r)) if diff.removed_auditallows and not args.stats: print(" Removed Auditallow Rules: {0}".format(len(diff.removed_auditallows))) for r in sorted(diff.removed_auditallows): print(" - {0}".format(r)) if diff.modified_auditallows and not args.stats: print(" Modified Auditallow Rules: {0}".format(len(diff.modified_auditallows))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_auditallows, key=lambda x: x.rule): perm_str = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perm_str) with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_auditallows del diff.removed_auditallows del diff.modified_auditallows if all_differences or args.auditallowxperm: if diff.added_auditallowxperms or diff.removed_auditallowxperms or \ diff.modified_auditallowxperms or args.auditallowxperm: print("Auditallowxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_auditallowxperms), len(diff.removed_auditallowxperms), len(diff.modified_auditallowxperms))) if diff.added_auditallowxperms and not args.stats: print(" Added Auditallowxperm Rules: {0}".format( len(diff.added_auditallowxperms))) for r in sorted(diff.added_auditallowxperms): print(" + {0}".format(r)) if diff.removed_auditallowxperms and not args.stats: print(" Removed Auditallowxperm Rules: {0}".format( len(diff.removed_auditallowxperms))) for r in sorted(diff.removed_auditallowxperms): print(" - {0}".format(r)) if diff.modified_auditallowxperms and not args.stats: print(" Modified Auditallowxperm Rules: {0}".format( len(diff.modified_auditallowxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_auditallowxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_auditallowxperms del diff.removed_auditallowxperms del diff.modified_auditallowxperms if all_differences or args.dontaudit: if diff.added_dontaudits or diff.removed_dontaudits or diff.modified_dontaudits or \ args.dontaudit: print("Dontaudit Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_dontaudits), len(diff.removed_dontaudits), len(diff.modified_dontaudits))) if diff.added_dontaudits and not args.stats: print(" Added Dontaudit Rules: {0}".format(len(diff.added_dontaudits))) for r in sorted(diff.added_dontaudits): print(" + {0}".format(r)) if diff.removed_dontaudits and not args.stats: print(" Removed Dontaudit Rules: {0}".format(len(diff.removed_dontaudits))) for r in sorted(diff.removed_dontaudits): print(" - {0}".format(r)) if diff.modified_dontaudits and not args.stats: print(" Modified Dontaudit Rules: {0}".format(len(diff.modified_dontaudits))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_dontaudits, key=lambda x: x.rule): perm_str = " ".join(chain((p for p in matched_perms), ("+" + p for p in added_perms), ("-" + p for p in removed_perms))) rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {{ {1} }};".format( rule, perm_str) with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_dontaudits del diff.removed_dontaudits del diff.modified_dontaudits if all_differences or args.dontauditxperm: if diff.added_dontauditxperms or diff.removed_dontauditxperms or \ diff.modified_dontauditxperms or args.dontauditxperm: print("Dontauditxperm Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_dontauditxperms), len(diff.removed_dontauditxperms), len(diff.modified_dontauditxperms))) if diff.added_dontauditxperms and not args.stats: print(" Added Dontauditxperm Rules: {0}".format( len(diff.added_dontauditxperms))) for r in sorted(diff.added_dontauditxperms): print(" + {0}".format(r)) if diff.removed_dontauditxperms and not args.stats: print(" Removed Dontauditxperm Rules: {0}".format( len(diff.removed_dontauditxperms))) for r in sorted(diff.removed_dontauditxperms): print(" - {0}".format(r)) if diff.modified_dontauditxperms and not args.stats: print(" Modified Dontauditxperm Rules: {0}".format( len(diff.modified_dontauditxperms))) for rule, added_perms, removed_perms, matched_perms in sorted( diff.modified_dontauditxperms, key=lambda x: x.rule): # Process the string representation of the sets # so hex representation and ranges are preserved. # Check if the perm sets have contents, otherwise # split on empty string will be an empty string. # Add brackets to added and removed permissions # in case there is a range of permissions. perms = [] if matched_perms: for p in str(matched_perms).split(" "): perms.append(p) if added_perms: for p in str(added_perms).split(" "): if '-' in p: perms.append("+[{0}]".format(p)) else: perms.append("+{0}".format(p)) if removed_perms: for p in str(removed_perms).split(" "): if '-' in p: perms.append("-[{0}]".format(p)) else: perms.append("-{0}".format(p)) rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} {{ {1} }};". \ format(rule, perms) print(" * {0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} " "{{ {1} }};".format(rule, " ".join(perms))) print() del diff.added_dontauditxperms del diff.removed_dontauditxperms del diff.modified_dontauditxperms if all_differences or args.type_trans: if diff.added_type_transitions or diff.removed_type_transitions or \ diff.modified_type_transitions or args.type_trans: print("Type_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_transitions), len(diff.removed_type_transitions), len(diff.modified_type_transitions))) if diff.added_type_transitions and not args.stats: print(" Added Type_transition Rules: {0}".format( len(diff.added_type_transitions))) for r in sorted(diff.added_type_transitions): print(" + {0}".format(r)) if diff.removed_type_transitions and not args.stats: print(" Removed Type_transition Rules: {0}".format( len(diff.removed_type_transitions))) for r in sorted(diff.removed_type_transitions): print(" - {0}".format(r)) if diff.modified_type_transitions and not args.stats: print(" Modified Type_transition Rules: {0}".format( len(diff.modified_type_transitions))) for rule, added_default, removed_default in sorted(diff.modified_type_transitions, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) with suppress(AttributeError): rule_string += " {0}".format(rule.filename) rule_string += ";" with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_type_transitions del diff.removed_type_transitions del diff.modified_type_transitions if all_differences or args.type_change: if diff.added_type_changes or diff.removed_type_changes or \ diff.modified_type_changes or args.type_change: print("Type_change Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_changes), len(diff.removed_type_changes), len(diff.modified_type_changes))) if diff.added_type_changes and not args.stats: print(" Added Type_change Rules: {0}".format(len(diff.added_type_changes))) for r in sorted(diff.added_type_changes): print(" + {0}".format(r)) if diff.removed_type_changes and not args.stats: print(" Removed Type_change Rules: {0}".format(len(diff.removed_type_changes))) for r in sorted(diff.removed_type_changes): print(" - {0}".format(r)) if diff.modified_type_changes and not args.stats: print(" Modified Type_change Rules: {0}".format(len(diff.modified_type_changes))) for rule, added_default, removed_default in sorted(diff.modified_type_changes, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) with suppress(AttributeError): rule_string += " {0}".format(rule.filename) rule_string += ";" with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_type_changes del diff.removed_type_changes del diff.modified_type_changes if all_differences or args.type_member: if diff.added_type_members or diff.removed_type_members or \ diff.modified_type_members or args.type_member: print("Type_member Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_type_members), len(diff.removed_type_members), len(diff.modified_type_members))) if diff.added_type_members and not args.stats: print(" Added Type_member Rules: {0}".format(len(diff.added_type_members))) for r in sorted(diff.added_type_members): print(" + {0}".format(r)) if diff.removed_type_members and not args.stats: print(" Removed Type_member Rules: {0}".format(len(diff.removed_type_members))) for r in sorted(diff.removed_type_members): print(" - {0}".format(r)) if diff.modified_type_members and not args.stats: print(" Modified Type_member Rules: {0}".format(len(diff.modified_type_members))) for rule, added_default, removed_default in sorted(diff.modified_type_members, key=lambda x: x.rule): rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) with suppress(AttributeError): rule_string += " {0}".format(rule.filename) rule_string += ";" with suppress(AttributeError): rule_string += " [ {0} ]".format(rule.conditional) print(" * {0}".format(rule_string)) print() del diff.added_type_members del diff.removed_type_members del diff.modified_type_members if all_differences or args.role_allow: if diff.added_role_allows or diff.removed_role_allows or args.role_allow: print("Role allow Rules ({0} Added, {1} Removed)".format( len(diff.added_role_allows), len(diff.removed_role_allows))) if diff.added_role_allows and not args.stats: print(" Added Role Allow Rules: {0}".format( len(diff.added_role_allows))) for r in sorted(diff.added_role_allows): print(" + {0}".format(r)) if diff.removed_role_allows and not args.stats: print(" Removed Role Allow Rules: {0}".format( len(diff.removed_role_allows))) for r in sorted(diff.removed_role_allows): print(" - {0}".format(r)) print() del diff.added_role_allows del diff.removed_role_allows if all_differences or args.role_trans: if diff.added_role_transitions or diff.removed_role_transitions or \ diff.modified_role_transitions or args.role_trans: print("Role_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_role_transitions), len(diff.removed_role_transitions), len(diff.modified_role_transitions))) if diff.added_role_transitions and not args.stats: print(" Added Role_transition Rules: {0}".format( len(diff.added_role_transitions))) for r in sorted(diff.added_role_transitions): print(" + {0}".format(r)) if diff.removed_role_transitions and not args.stats: print(" Removed Role_transition Rules: {0}".format( len(diff.removed_role_transitions))) for r in sorted(diff.removed_role_transitions): print(" - {0}".format(r)) if diff.modified_role_transitions and not args.stats: print(" Modified Role_transition Rules: {0}".format( len(diff.modified_role_transitions))) for rule, added_default, removed_default in sorted(diff.modified_role_transitions, key=lambda x: x.rule): rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} +{1} -{2}".format( rule, added_default, removed_default) print(" * {0}".format(rule_string)) print() del diff.added_role_transitions del diff.removed_role_transitions del diff.modified_role_transitions if all_differences or args.range_trans: if diff.added_range_transitions or diff.removed_range_transitions or \ diff.modified_range_transitions or args.range_trans: print("Range_transition Rules ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_range_transitions), len(diff.removed_range_transitions), len(diff.modified_range_transitions))) if diff.added_range_transitions and not args.stats: print(" Added Range_transition Rules: {0}".format( len(diff.added_range_transitions))) for r in sorted(diff.added_range_transitions): print(" + {0}".format(r)) if diff.removed_range_transitions and not args.stats: print(" Removed Range_transition Rules: {0}".format( len(diff.removed_range_transitions))) for r in sorted(diff.removed_range_transitions): print(" - {0}".format(r)) if diff.modified_range_transitions and not args.stats: print(" Modified Range_transition Rules: {0}".format( len(diff.modified_range_transitions))) for rule, added_default, removed_default in sorted(diff.modified_range_transitions, key=lambda x: x.rule): # added brackets around range change for clarity since ranges # can have '-' and spaces. rule_string = \ "{0.ruletype} {0.source} {0.target}:{0.tclass} +[{1}] -[{2}]".format( rule, added_default, removed_default) print(" * {0}".format(rule_string)) print() del diff.added_range_transitions del diff.removed_range_transitions del diff.modified_range_transitions if all_differences or args.constrain: if diff.added_constrains or diff.removed_constrains or args.constrain: print("Constraints ({0} Added, {1} Removed)".format( len(diff.added_constrains), len(diff.removed_constrains))) if diff.added_constrains and not args.stats: print(" Added Constraints: {0}".format( len(diff.added_constrains))) for r in sorted(diff.added_constrains): print(" + {0}".format(r)) if diff.removed_constrains and not args.stats: print(" Removed Constraints: {0}".format( len(diff.removed_constrains))) for r in sorted(diff.removed_constrains): print(" - {0}".format(r)) print() del diff.added_constrains del diff.removed_constrains if all_differences or args.mlsconstrain: if diff.added_mlsconstrains or diff.removed_mlsconstrains or args.mlsconstrain: print("MLS Constraints ({0} Added, {1} Removed)".format( len(diff.added_mlsconstrains), len(diff.removed_mlsconstrains))) if diff.added_mlsconstrains and not args.stats: print(" Added MLS Constraints: {0}".format( len(diff.added_mlsconstrains))) for r in sorted(diff.added_mlsconstrains): print(" + {0}".format(r)) if diff.removed_mlsconstrains and not args.stats: print(" Removed MLS Constraints: {0}".format( len(diff.removed_mlsconstrains))) for r in sorted(diff.removed_mlsconstrains): print(" - {0}".format(r)) print() del diff.added_mlsconstrains del diff.removed_mlsconstrains if all_differences or args.validatetrans: if diff.added_validatetrans or diff.removed_validatetrans or args.validatetrans: print("Validatetrans ({0} Added, {1} Removed)".format( len(diff.added_validatetrans), len(diff.removed_validatetrans))) if diff.added_validatetrans and not args.stats: print(" Added Validatetrans: {0}".format( len(diff.added_validatetrans))) for r in sorted(diff.added_validatetrans): print(" + {0}".format(r)) if diff.removed_validatetrans and not args.stats: print(" Removed Validatetrans: {0}".format( len(diff.removed_validatetrans))) for r in sorted(diff.removed_validatetrans): print(" - {0}".format(r)) print() del diff.added_validatetrans del diff.removed_validatetrans if all_differences or args.mlsvalidatetrans: if diff.added_mlsvalidatetrans or diff.removed_mlsvalidatetrans or args.mlsvalidatetrans: print("MLS Validatetrans ({0} Added, {1} Removed)".format( len(diff.added_mlsvalidatetrans), len(diff.removed_mlsvalidatetrans))) if diff.added_mlsvalidatetrans and not args.stats: print(" Added MLS Validatetrans: {0}".format( len(diff.added_mlsvalidatetrans))) for r in sorted(diff.added_mlsvalidatetrans): print(" + {0}".format(r)) if diff.removed_mlsvalidatetrans and not args.stats: print(" Removed MLS Validatetrans: {0}".format( len(diff.removed_mlsvalidatetrans))) for r in sorted(diff.removed_mlsvalidatetrans): print(" - {0}".format(r)) print() del diff.added_mlsvalidatetrans del diff.removed_mlsvalidatetrans if all_differences or args.initialsid: if diff.added_initialsids or diff.removed_initialsids or diff.modified_initialsids \ or args.initialsid: print("Initial SIDs ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_initialsids), len(diff.removed_initialsids), len(diff.modified_initialsids))) if diff.added_initialsids and not args.stats: print(" Added Initial SIDs: {0}".format(len(diff.added_initialsids))) for s in sorted(diff.added_initialsids): print(" + {0}".format(s.statement())) if diff.removed_initialsids and not args.stats: print(" Removed Initial SIDs: {0}".format(len(diff.removed_initialsids))) for s in sorted(diff.removed_initialsids): print(" - {0}".format(s.statement())) if diff.modified_initialsids and not args.stats: print(" Modified Initial SIDs: {0}".format(len(diff.modified_initialsids))) for name, mod in sorted(diff.modified_initialsids.items()): print(" * {0} +[{1.added_context}] -[{1.removed_context}];".format( name, mod)) print() del diff.added_initialsids del diff.removed_initialsids del diff.modified_initialsids if all_differences or args.ibendportcon: if diff.added_ibendportcons or diff.removed_ibendportcons or diff.modified_ibendportcons \ or args.ibendportcon: print("Ibendportcons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_ibendportcons), len(diff.removed_ibendportcons), len(diff.modified_ibendportcons))) if diff.added_ibendportcons and not args.stats: print(" Added Ibendportcons: {0}".format(len(diff.added_ibendportcons))) for s in sorted(diff.added_ibendportcons): print(" + {0}".format(s.statement())) if diff.removed_ibendportcons and not args.stats: print(" Removed Ibendportcons: {0}".format(len(diff.removed_ibendportcons))) for s in sorted(diff.removed_ibendportcons): print(" - {0}".format(s.statement())) if diff.modified_ibendportcons and not args.stats: print(" Modified Ibendportcons: {0}".format(len(diff.modified_ibendportcons))) for entry in sorted(diff.modified_ibendportcons, key=lambda x: x.rule): print(" * ibendportcon {0.rule.name} {0.rule.port} " "+[{0.added_context}] -[{0.removed_context}]".format(entry)) print() del diff.added_ibendportcons del diff.removed_ibendportcons del diff.modified_ibendportcons if all_differences or args.ibpkeycon: if diff.added_ibpkeycons or diff.removed_ibpkeycons or diff.modified_ibpkeycons \ or args.ibpkeycon: print("Ibpkeycons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_ibpkeycons), len(diff.removed_ibpkeycons), len(diff.modified_ibpkeycons))) if diff.added_ibpkeycons and not args.stats: print(" Added Ibpkeycons: {0}".format(len(diff.added_ibpkeycons))) for s in sorted(diff.added_ibpkeycons): print(" + {0}".format(s.statement())) if diff.removed_ibpkeycons and not args.stats: print(" Removed Ibpkeycons: {0}".format(len(diff.removed_ibpkeycons))) for s in sorted(diff.removed_ibpkeycons): print(" - {0}".format(s.statement())) if diff.modified_ibpkeycons and not args.stats: print(" Modified Ibpkeycons: {0}".format(len(diff.modified_ibpkeycons))) for entry in sorted(diff.modified_ibpkeycons, key=lambda x: x.rule): if entry.rule.pkeys.low == entry.rule.pkeys.high: print(" * ibpkeycon {0.rule.subnet_prefix} {0.rule.pkeys.low:#x} " "+[{0.added_context}] -[{0.removed_context}]".format(entry)) else: print(" * ibpkeycon {0.rule.subnet_prefix} " "{0.rule.pkeys.low:#x}-{0.rule.pkeys.high:#x} " "+[{0.added_context}] -[{0.removed_context}]".format(entry)) print() del diff.added_ibpkeycons del diff.removed_ibpkeycons del diff.modified_ibpkeycons if all_differences or args.fs_use: if diff.added_fs_uses or diff.removed_fs_uses or diff.modified_fs_uses \ or args.fs_use: print("Fs_use ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_fs_uses), len(diff.removed_fs_uses), len(diff.modified_fs_uses))) if diff.added_fs_uses and not args.stats: print(" Added Fs_use: {0}".format(len(diff.added_fs_uses))) for s in sorted(diff.added_fs_uses): print(" + {0}".format(s)) if diff.removed_fs_uses and not args.stats: print(" Removed Fs_use: {0}".format(len(diff.removed_fs_uses))) for s in sorted(diff.removed_fs_uses): print(" - {0}".format(s)) if diff.modified_fs_uses and not args.stats: print(" Modified Fs_use: {0}".format(len(diff.modified_fs_uses))) for entry in sorted(diff.modified_fs_uses, key=lambda x: x.rule): print(" * {0.ruletype} {0.fs} +[{1}] -[{2}];".format( entry.rule, entry.added_context, entry.removed_context)) print() del diff.added_fs_uses del diff.removed_fs_uses del diff.modified_fs_uses if all_differences or args.genfscon: if diff.added_genfscons or diff.removed_genfscons or diff.modified_genfscons \ or args.genfscon: print("Genfscons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_genfscons), len(diff.removed_genfscons), len(diff.modified_genfscons))) if diff.added_genfscons and not args.stats: print(" Added Genfscons: {0}".format(len(diff.added_genfscons))) for s in sorted(diff.added_genfscons): print(" + {0}".format(s)) if diff.removed_genfscons and not args.stats: print(" Removed Genfscons: {0}".format(len(diff.removed_genfscons))) for s in sorted(diff.removed_genfscons): print(" - {0}".format(s)) if diff.modified_genfscons and not args.stats: print(" Modified Genfscons: {0}".format(len(diff.modified_genfscons))) for entry in sorted(diff.modified_genfscons, key=lambda x: x.rule): print(" * genfscon {0.fs} {0.path} {0.filetype} +[{1}] -[{2}];".format( entry.rule, entry.added_context, entry.removed_context)) print() del diff.added_genfscons del diff.removed_genfscons del diff.modified_genfscons if all_differences or args.netifcon: if diff.added_netifcons or diff.removed_netifcons or \ diff.modified_netifcons or args.netifcon: print("Netifcons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_netifcons), len(diff.removed_netifcons), len(diff.modified_netifcons))) if diff.added_netifcons and not args.stats: print(" Added Netifcons: {0}".format(len(diff.added_netifcons))) for n in sorted(diff.added_netifcons): print(" + {0}".format(n)) if diff.removed_netifcons and not args.stats: print(" Removed Netifcons: {0}".format(len(diff.removed_netifcons))) for n in sorted(diff.removed_netifcons): print(" - {0}".format(n)) if diff.modified_netifcons and not args.stats: print(" Modified Netifcons: {0}".format(len(diff.modified_netifcons))) for entry in sorted(diff.modified_netifcons, key=lambda x: x.rule): # This output is different than other statements because # it becomes difficult to read if this was condensed # into a single line, especially if both contexts # are modified. change = [] if entry.removed_context: change.append("Modified Context") if entry.removed_packet: change.append("Modified Packet Context") print(" * {0.netif} ({1})".format(entry.rule, ", ".join(change))) if entry.removed_context: print(" Context:") print(" + {0}".format(entry.added_context)) print(" - {0}".format(entry.removed_context)) if entry.removed_packet: print(" Packet Context:") print(" + {0}".format(entry.added_packet)) print(" - {0}".format(entry.removed_packet)) print() del diff.added_netifcons del diff.removed_netifcons del diff.modified_netifcons if all_differences or args.nodecon: if diff.added_nodecons or diff.removed_nodecons or diff.modified_nodecons \ or args.nodecon: print("Nodecons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_nodecons), len(diff.removed_nodecons), len(diff.modified_nodecons))) if diff.added_nodecons and not args.stats: print(" Added Nodecons: {0}".format(len(diff.added_nodecons))) for n in sorted(diff.added_nodecons): print(" + {0}".format(n)) if diff.removed_nodecons and not args.stats: print(" Removed Nodecons: {0}".format(len(diff.removed_nodecons))) for n in sorted(diff.removed_nodecons): print(" - {0}".format(n)) if diff.modified_nodecons and not args.stats: print(" Modified Nodecons: {0}".format(len(diff.modified_nodecons))) for entry in sorted(diff.modified_nodecons, key=lambda x: x.rule): print(" * nodecon {0} +[{1.added_context}] -[{1.removed_context}];".format( entry.rule.network.with_netmask.replace("/", " "), entry)) print() del diff.added_nodecons del diff.removed_nodecons del diff.modified_nodecons if all_differences or args.portcon: if diff.added_portcons or diff.removed_portcons or diff.modified_portcons \ or args.portcon: print("Portcons ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_portcons), len(diff.removed_portcons), len(diff.modified_portcons))) if diff.added_portcons and not args.stats: print(" Added Portcons: {0}".format(len(diff.added_portcons))) for n in sorted(diff.added_portcons): print(" + {0}".format(n)) if diff.removed_portcons and not args.stats: print(" Removed Portcons: {0}".format(len(diff.removed_portcons))) for n in sorted(diff.removed_portcons): print(" - {0}".format(n)) if diff.modified_portcons and not args.stats: print(" Modified Portcons: {0}".format(len(diff.modified_portcons))) for con, added_context, removed_context in sorted(diff.modified_portcons, key=lambda x: x.rule): low, high = con.ports if low == high: print(" * portcon {0.protocol} {1} +[{2}] -[{3}];".format( con, low, added_context, removed_context)) else: print(" * portcon {0.protocol} {1}-{2} +[{3}] -[{4}];".format( con, low, high, added_context, removed_context)) print() del diff.added_portcons del diff.removed_portcons del diff.modified_portcons if all_differences or args.polcap: if diff.added_polcaps or diff.removed_polcaps or args.polcap: print("Policy Capabilities ({0} Added, {1} Removed)".format( len(diff.added_polcaps), len(diff.removed_polcaps))) if diff.added_polcaps and not args.stats: print(" Added Policy Capabilities: {0}".format(len(diff.added_polcaps))) for n in sorted(diff.added_polcaps): print(" + {0}".format(n)) if diff.removed_polcaps and not args.stats: print(" Removed Policy Capabilities: {0}".format(len(diff.removed_polcaps))) for n in sorted(diff.removed_polcaps): print(" - {0}".format(n)) print() del diff.added_polcaps del diff.removed_polcaps if all_differences or args.default: if diff.added_defaults or diff.removed_defaults or diff.modified_defaults or args.default: print("Defaults ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_defaults), len(diff.removed_defaults), len(diff.modified_defaults))) if diff.added_defaults and not args.stats: print(" Added Defaults: {0}".format(len(diff.added_defaults))) for d in sorted(diff.added_defaults): print(" + {0}".format(d)) if diff.removed_defaults and not args.stats: print(" Removed Defaults: {0}".format(len(diff.removed_defaults))) for d in sorted(diff.removed_defaults): print(" - {0}".format(d)) if diff.modified_defaults and not args.stats: print(" Modified Defaults: {0}".format(len(diff.modified_defaults))) for default, added_default, removed_default, added_range, removed_range in sorted( diff.modified_defaults, key=lambda x: x.rule): line = " * {0.ruletype} {0.tclass} ".format(default) if removed_default: line += "+{0} -{1}".format(added_default, removed_default) else: line += default.default.name if removed_range: line += " +{0} -{1};".format(added_range, removed_range) else: try: line += " {0};".format(default.default_range) except AttributeError: line += ";" print(line) print() del diff.added_defaults del diff.removed_defaults del diff.modified_defaults if all_differences or args.typebounds: if diff.added_typebounds or diff.removed_typebounds or args.typebounds: print("Typebounds ({0} Added, {1} Removed, {2} Modified)".format( len(diff.added_typebounds), len(diff.removed_typebounds), len(diff.modified_typebounds))) if diff.added_typebounds and not args.stats: print(" Added Typebounds: {0}".format(len(diff.added_typebounds))) for d in sorted(diff.added_typebounds): print(" + {0}".format(d)) if diff.removed_typebounds and not args.stats: print(" Removed Typebounds: {0}".format(len(diff.removed_typebounds))) for d in sorted(diff.removed_typebounds): print(" - {0}".format(d)) if diff.modified_typebounds and not args.stats: print(" Modified Typebounds: {0}".format(len(diff.modified_typebounds))) for bound, added_bound, removed_bound in sorted( diff.modified_typebounds, key=lambda x: x.rule): print(" * {0.ruletype} +{1} -{2} {0.child};".format( bound, added_bound, removed_bound)) print() del diff.added_typebounds del diff.removed_typebounds except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/sedta000077500000000000000000000131021402045477700142440ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import sys import argparse import logging import signal import setools def print_transition(trans: setools.DomainTransition) -> None: if trans.transition: print("Domain transition rule(s):") for t in trans.transition: print(t) if trans.setexec: print("\nSet execution context rule(s):") for s in trans.setexec: print(s) for entrypoint in trans.entrypoints: print("\nEntrypoint {0}:".format(entrypoint.name)) print("\tDomain entrypoint rule(s):") for e in entrypoint.entrypoint: print("\t{0}".format(e)) print("\n\tFile execute rule(s):") for e in entrypoint.execute: print("\t{0}".format(e)) if entrypoint.type_transition: print("\n\tType transition rule(s):") for t in entrypoint.type_transition: print("\t{0}".format(t)) print() if trans.dyntransition: print("Dynamic transition rule(s):") for d in trans.dyntransition: print(d) print("\nSet current process context rule(s):") for s in trans.setcurrent: print(s) print() print() signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser( description="SELinux policy domain transition analysis tool.", epilog="If no analysis is selected, all forward transitions out of the source will be printed.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("-p", "--policy", help="Path to SELinux policy to analyze.") parser.add_argument("-s", "--source", help="Source type of the analysis.", required=True) parser.add_argument("-t", "--target", help="Target type of the analysis.") parser.add_argument("--stats", action="store_true", help="Display statistics at the end of the analysis.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") alg = parser.add_argument_group("Analysis algorithm") alg.add_argument("-S", "--shortest_path", action="store_true", help="Calculate all shortest paths.") alg.add_argument("-A", "--all_paths", type=int, metavar="MAX_STEPS", help="Calculate all paths, with the specified maximum path length. (Expensive)") opts = parser.add_argument_group("Analysis options") opts.add_argument("-r", "--reverse", action="store_true", default=False, help="Perform a reverse DTA.") opts.add_argument("-l", "--limit_trans", default=0, type=int, help="Limit to the specified number of transitions. Default is unlimited.") opts.add_argument("exclude", help="List of excluded types in the analysis.", nargs="*") args = parser.parse_args() if not args.target and (args.shortest_path or args.all_paths): parser.error("The target type must be specified to determine a path.") if args.target and not (args.shortest_path or args.all_paths): parser.error("An algorithm must be specified to determine a path.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) g = setools.DomainTransitionAnalysis(p, reverse=args.reverse, exclude=args.exclude) if args.shortest_path or args.all_paths: if args.shortest_path: paths = g.all_shortest_paths(args.source, args.target) else: paths = g.all_paths(args.source, args.target, args.all_paths) i = 0 for i, path in enumerate(paths, start=1): print("Domain transition path {0}:".format(i)) for stepnum, step in enumerate(path, start=1): print("Step {0}: {1} -> {2}\n".format(stepnum, step.source, step.target)) print_transition(step) if args.limit_trans and i >= args.limit_trans: break print(i, "domain transition path(s) found.") else: # single transition transitions = g.transitions(args.source) i = 0 for i, step in enumerate(transitions, start=1): print("Transition {0}: {1} -> {2}\n".format(i, step.source, step.target)) print_transition(step) if args.limit_trans and i >= args.limit_trans: break print(i, "domain transition(s) found.") if args.stats: print("\nGraph statistics:") print(g.get_stats()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/seinfo000077500000000000000000000451221402045477700144360ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # Copyright 2018-2019, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import setools import argparse import sys import logging import signal import ipaddress from typing import Callable, List, Tuple def expand_attr(attr): """Render type and role attributes.""" items = "\n\t".join(sorted(str(i) for i in attr.expand())) contents = items if items else "" return "{0}\n\t{1}".format(attr.statement(), contents) signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser(description="SELinux policy information tool.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", help="Path to the SELinux policy to query.", nargs="?") parser.add_argument("-x", "--expand", action="store_true", help="Print additional information about the specified components.") parser.add_argument("--flat", help="Print without item count nor indentation.", dest="flat", default=False, action="store_true") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") queries = parser.add_argument_group("Component Queries") queries.add_argument("-a", "--attribute", help="Print type attributes.", dest="typeattrquery", nargs='?', const=True, metavar="ATTR") queries.add_argument("-b", "--bool", help="Print Booleans.", dest="boolquery", nargs='?', const=True, metavar="BOOL") queries.add_argument("-c", "--class", help="Print object classes.", dest="classquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("-r", "--role", help="Print roles.", dest="rolequery", nargs='?', const=True, metavar="ROLE") queries.add_argument("-t", "--type", help="Print types.", dest="typequery", nargs='?', const=True, metavar="TYPE") queries.add_argument("-u", "--user", help="Print users.", dest="userquery", nargs='?', const=True, metavar="USER") queries.add_argument("--category", help="Print MLS categories.", dest="mlscatsquery", nargs='?', const=True, metavar="CAT") queries.add_argument("--common", help="Print common permission set.", dest="commonquery", nargs='?', const=True, metavar="COMMON") queries.add_argument("--constrain", help="Print constraints.", dest="constraintquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--default", help="Print default_* rules.", dest="defaultquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--fs_use", help="Print fs_use statements.", dest="fsusequery", nargs='?', const=True, metavar="FS_TYPE") queries.add_argument("--genfscon", help="Print genfscon statements.", dest="genfsconquery", nargs='?', const=True, metavar="FS_TYPE") queries.add_argument("--ibpkeycon", help="Infiniband pkey statements.", dest="ibpkeyconquery", nargs='?', const=True, metavar="PKEY[-PKEY]") queries.add_argument("--ibendportcon", help="Infiniband endport statements.", dest="ibendportconquery", nargs='?', const=True, metavar="NAME") queries.add_argument("--initialsid", help="Print initial SIDs (contexts).", dest="initialsidquery", nargs='?', const=True, metavar="NAME") queries.add_argument("--netifcon", help="Print netifcon statements.", dest="netifconquery", nargs='?', const=True, metavar="DEVICE") queries.add_argument("--nodecon", help="Print nodecon statements.", dest="nodeconquery", nargs='?', const=True, metavar="ADDR") queries.add_argument("--permissive", help="Print permissive types.", dest="permissivequery", nargs='?', const=True, metavar="TYPE") queries.add_argument("--polcap", help="Print policy capabilities.", dest="polcapquery", nargs='?', const=True, metavar="NAME") queries.add_argument("--portcon", help="Print portcon statements.", dest="portconquery", nargs='?', const=True, metavar="PORTNUM[-PORTNUM]") queries.add_argument("--sensitivity", help="Print MLS sensitivities.", dest="mlssensquery", nargs='?', const=True, metavar="SENS") queries.add_argument("--typebounds", help="Print typebounds statements.", dest="typeboundsquery", nargs='?', const=True, metavar="BOUND_TYPE") queries.add_argument("--validatetrans", help="Print validatetrans.", dest="validatetransquery", nargs='?', const=True, metavar="CLASS") queries.add_argument("--all", help="Print all of the above. On a Xen policy, the Xen components " "will also be printed", dest="all", default=False, action="store_true") xen = parser.add_argument_group("Xen Component Queries") xen.add_argument("--ioportcon", help="Print all ioportcon statements.", dest="ioportconquery", default=False, action="store_true") xen.add_argument("--iomemcon", help="Print all iomemcon statements.", dest="iomemconquery", default=False, action="store_true") xen.add_argument("--pcidevicecon", help="Print all pcidevicecon statements.", dest="pcideviceconquery", default=False, action="store_true") xen.add_argument("--pirqcon", help="Print all pirqcon statements.", dest="pirqconquery", default=False, action="store_true") xen.add_argument("--devicetreecon", help="Print all devicetreecon statements.", dest="devicetreeconquery", default=False, action="store_true") args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) components: List[Tuple[str, setools.PolicyQuery, Callable]] = [] if args.boolquery or args.all: bq = setools.BoolQuery(p) if isinstance(args.boolquery, str): if args.policy: bq.name = args.boolquery else: # try to find substitutions for old boolean names bq.name = setools.policyrep.lookup_boolean_name_sub(args.boolquery) components.append(("Booleans", bq, lambda x: x.statement())) if args.mlscatsquery or args.all: mcq = setools.CategoryQuery(p, alias_deref=True) if isinstance(args.mlscatsquery, str): mcq.name = args.mlscatsquery components.append(("Categories", mcq, lambda x: x.statement())) if args.classquery or args.all: ocq = setools.ObjClassQuery(p) if isinstance(args.classquery, str): ocq.name = args.classquery components.append(("Classes", ocq, lambda x: x.statement())) if args.commonquery or args.all: cq = setools.CommonQuery(p) if isinstance(args.commonquery, str): cq.name = args.commonquery components.append(("Commons", cq, lambda x: x.statement())) if args.constraintquery or args.all: coq = setools.ConstraintQuery( p, ruletype=[setools.ConstraintRuletype.constrain, setools.ConstraintRuletype.mlsconstrain]) if isinstance(args.constraintquery, str): coq.tclass = [args.constraintquery] components.append(("Constraints", coq, lambda x: x.statement())) if args.defaultquery or args.all: dq: setools.DefaultQuery = setools.DefaultQuery(p) if isinstance(args.defaultquery, str): dq.tclass = [args.defaultquery] components.append(("Default rules", dq, lambda x: x.statement())) if args.fsusequery or args.all: fq: setools.FSUseQuery = setools.FSUseQuery(p) if isinstance(args.fsusequery, str): fq.fs = args.fsusequery components.append(("Fs_use", fq, lambda x: x.statement())) if args.genfsconquery or args.all: gq: setools.GenfsconQuery = setools.GenfsconQuery(p) if isinstance(args.genfsconquery, str): gq.fs = args.genfsconquery components.append(("Genfscon", gq, lambda x: x.statement())) if args.ibendportconquery or args.all: ibepq: setools.IbendportconQuery = setools.IbendportconQuery(p) if isinstance(args.ibendportconquery, str): ibepq.name = args.ibendportconquery components.append(("Ibendportcon", ibepq, lambda x: x.statement())) if args.ibpkeyconquery or args.all: ibpkq = setools.IbpkeyconQuery(p) if isinstance(args.ibpkeyconquery, str): try: pkeys = [int(i, 16) for i in args.ibpkeyconquery.split("-")] except ValueError: parser.error("Enter a pkey number or range, e.g. 0x22 or 0x6000-0x6020") if len(pkeys) == 2: ibpkq.pkeys = setools.IbpkeyconRange(pkeys) elif len(pkeys) == 1: ibpkq.pkeys = setools.IbpkeyconRange(pkeys[0], pkeys[0]) else: parser.error("Enter a pkey number or range, e.g. 0x22 or 0x6000-0x6020") components.append(("Ibpkeycon", ibpkq, lambda x: x.statement())) if args.initialsidquery or args.all: isidq = setools.InitialSIDQuery(p) if isinstance(args.initialsidquery, str): isidq.name = args.initialsidquery components.append(("Initial SIDs", isidq, lambda x: x.statement())) if args.netifconquery or args.all: netifq = setools.NetifconQuery(p) if isinstance(args.netifconquery, str): netifq.name = args.netifconquery components.append(("Netifcon", netifq, lambda x: x.statement())) if args.nodeconquery or args.all: nodeq = setools.NodeconQuery(p) if isinstance(args.nodeconquery, str): nodeq.network = ipaddress.ip_network(args.nodeconquery) components.append(("Nodecon", nodeq, lambda x: x.statement())) if args.permissivequery or args.all: permq = setools.TypeQuery(p, permissive=True, match_permissive=True) if isinstance(args.permissivequery, str): permq.name = args.permissivequery components.append(("Permissive Types", permq, lambda x: x.statement())) if args.polcapquery or args.all: capq = setools.PolCapQuery(p) if isinstance(args.polcapquery, str): capq.name = args.polcapquery components.append(("Polcap", capq, lambda x: x.statement())) if args.portconquery or args.all: pcq = setools.PortconQuery(p, ports_subset=True) if isinstance(args.portconquery, str): try: ports = [int(i) for i in args.portconquery.split("-")] except ValueError: parser.error("Enter a port number or range, e.g. 22 or 6000-6020") if len(ports) == 2: pcq.ports = setools.PortconRange(ports) elif len(ports) == 1: pcq.ports = setools.PortconRange(ports[0], ports[0]) else: parser.error("Enter a port number or range, e.g. 22 or 6000-6020") components.append(("Portcon", pcq, lambda x: x.statement())) if args.rolequery or args.all: rq = setools.RoleQuery(p) if isinstance(args.rolequery, str): rq.name = args.rolequery components.append(("Roles", rq, lambda x: x.statement())) if args.mlssensquery or args.all: msq = setools.SensitivityQuery(p, alias_deref=True) if isinstance(args.mlssensquery, str): msq.name = args.mlssensquery components.append(("Sensitivities", msq, lambda x: x.statement())) if args.typeboundsquery or args.all: tbq = setools.BoundsQuery( p, ruletype=[setools.BoundsRuletype.typebounds]) if isinstance(args.typeboundsquery, str): tbq.child = args.typeboundsquery components.append(("Typebounds", tbq, lambda x: x.statement())) if args.typequery or args.all: tq = setools.TypeQuery(p, alias_deref=True) if isinstance(args.typequery, str): tq.name = args.typequery components.append(("Types", tq, lambda x: x.statement())) if args.typeattrquery or args.all: taq = setools.TypeAttributeQuery(p) if isinstance(args.typeattrquery, str): taq.name = args.typeattrquery components.append(("Type Attributes", taq, expand_attr)) if args.userquery or args.all: uq = setools.UserQuery(p) if isinstance(args.userquery, str): uq.name = args.userquery components.append(("Users", uq, lambda x: x.statement())) if args.validatetransquery or args.all: vtq = setools.ConstraintQuery( p, ruletype=[setools.ConstraintRuletype.validatetrans, setools.ConstraintRuletype.mlsvalidatetrans]) if isinstance(args.validatetransquery, str): vtq.tclass = [args.validatetransquery] components.append(("Validatetrans", vtq, lambda x: x.statement())) if p.target_platform == "xen": if args.ioportconquery or args.all: xiopq = setools.IoportconQuery(p) components.append(("Ioportcon", xiopq, lambda x: x.statement())) if args.iomemconquery or args.all: xiomq = setools.IomemconQuery(p) components.append(("Iomemcon", xiomq, lambda x: x.statement())) if args.pcideviceconquery or args.all: pcidq = setools.PcideviceconQuery(p) components.append(("Pcidevicecon", pcidq, lambda x: x.statement())) if args.pirqconquery or args.all: pirqq = setools.PirqconQuery(p) components.append(("Pirqcon", pirqq, lambda x: x.statement())) if args.devicetreeconquery or args.all: dtq = setools.DevicetreeconQuery(p) components.append(("Devicetreecon", dtq, lambda x: x.statement())) if (not components or args.all) and not args.flat: mls = "enabled" if p.mls else "disabled" print("Statistics for policy file: {0}".format(p)) print("Policy Version: {0} (MLS {1})".format(p.version, mls)) print("Target Policy: {0}".format(p.target_platform)) print("Handle unknown classes: {0}".format(p.handle_unknown)) print(" Classes: {0:7} Permissions: {1:7}".format( p.class_count, p.permission_count)) print(" Sensitivities: {0:7} Categories: {1:7}".format( p.level_count, p.category_count)) print(" Types: {0:7} Attributes: {1:7}".format( p.type_count, p.type_attribute_count)) print(" Users: {0:7} Roles: {1:7}".format( p.user_count, p.role_count)) print(" Booleans: {0:7} Cond. Expr.: {1:7}".format( p.boolean_count, p.conditional_count)) print(" Allow: {0:7} Neverallow: {1:7}".format( p.allow_count, p.neverallow_count)) print(" Auditallow: {0:7} Dontaudit: {1:7}".format( p.auditallow_count, p.dontaudit_count)) print(" Type_trans: {0:7} Type_change: {1:7}".format( p.type_transition_count, p.type_change_count)) print(" Type_member: {0:7} Range_trans: {1:7}".format( p.type_member_count, p.range_transition_count)) print(" Role allow: {0:7} Role_trans: {1:7}".format( p.role_allow_count, p.role_transition_count)) print(" Constraints: {0:7} Validatetrans: {1:7}".format( p.constraint_count, p.validatetrans_count)) print(" MLS Constrain: {0:7} MLS Val. Tran: {1:7}".format( p.mlsconstraint_count, p.mlsvalidatetrans_count)) print(" Permissives: {0:7} Polcap: {1:7}".format( p.permissives_count, p.polcap_count)) print(" Defaults: {0:7} Typebounds: {1:7}".format( p.default_count, p.typebounds_count)) if p.target_platform == setools.PolicyTarget.selinux: print(" Allowxperm: {0:7} Neverallowxperm: {1:7}".format( p.allowxperm_count, p.neverallowxperm_count)) print(" Auditallowxperm: {0:7} Dontauditxperm: {1:7}".format( p.auditallowxperm_count, p.dontauditxperm_count)) print(" Ibendportcon: {0:7} Ibpkeycon: {1:7}".format( p.ibendportcon_count, p.ibpkeycon_count)) print(" Initial SIDs: {0:7} Fs_use: {1:7}".format( p.initialsids_count, p.fs_use_count)) print(" Genfscon: {0:7} Portcon: {1:7}".format( p.genfscon_count, p.portcon_count)) print(" Netifcon: {0:7} Nodecon: {1:7}".format( p.netifcon_count, p.nodecon_count)) elif p.target_platform == setools.PolicyTarget.xen: print(" Initial SIDs: {0:7} Devicetreecon: {1:7}".format( p.initialsids_count, p.devicetreecon_count)) print(" Iomemcon: {0:7} Ioportcon: {1:7}".format( p.iomemcon_count, p.ioportcon_count)) print(" Pcidevicecon: {0:7} Pirqcon: {1:7}".format( p.pcidevicecon_count, p.pirqcon_count)) for desc, component, expander in components: results = sorted(component.results()) if not args.flat: print("\n{0}: {1}".format(desc, len(results))) for item in results: result = expander(item) if args.expand else item strfmt = " {0}" if not args.flat else "{0}" print(strfmt.format(result)) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/seinfoflow000077500000000000000000000133431402045477700153260ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import setools import argparse import sys import logging import signal from typing import Dict, Optional signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser( description="SELinux policy information flow analysis tool.", epilog="If no analysis is selected, all information flow out of the source will be printed.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("--stats", action="store_true", help="Display statistics at the end of the analysis.") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") settings = parser.add_argument_group("Analysis settings") settings.add_argument("-p", "--policy", help="Path to SELinux policy to analyze.") settings.add_argument("-m", "--map", required=True, help="Path to permission map file.") settings.add_argument("-s", "--source", required=True, help="Source type of the analysis.") settings.add_argument("-t", "--target", default="", help="Target type of the analysis.") alg = parser.add_argument_group("Analysis algorithm") alg.add_argument("-S", "--shortest_path", action="store_true", help="Calculate all shortest paths.") alg.add_argument("-A", "--all_paths", type=int, metavar="MAX_STEPS", help="Calculate all paths, with the specified maximum path length. (Expensive)") opts = parser.add_argument_group("Analysis options") opts.add_argument("-w", "--min_weight", default=3, type=int, help="Minimum permission weight. Default is 3.") opts.add_argument("-l", "--limit_flows", default=0, type=int, help="Limit to the specified number of flows. Default is unlimited.") opts.add_argument("-b", "--booleans", default=None, help="Specify the boolean values to use." " Options are default, or \"foo:true,bar:false...\"") opts.add_argument("exclude", nargs="*", help="List of excluded types in the analysis.") args = parser.parse_args() if not args.target and (args.shortest_path or args.all_paths): parser.error("The target type must be specified to determine a path.") if args.target and not (args.shortest_path or args.all_paths): parser.error("A target type is not used for flows in/out of a type.") if args.limit_flows < 0: parser.error("Limit on information flows cannot be negative.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') booleans: Optional[Dict[str, bool]] = None if args.booleans == 'default': booleans = {} elif args.booleans is not None: booleans = {} for boolean in args.booleans.split(','): try: key, value = boolean.split(':') if value.lower() == 'true': booleans[key] = True elif value.lower() == 'false': booleans[key] = False else: parser.error("Conditional value must be true or false.") except ValueError: parser.error("Expected boolean format foo:true,bar:false") try: p = setools.SELinuxPolicy(args.policy) m = setools.PermissionMap(args.map) g = setools.InfoFlowAnalysis(p, m, min_weight=args.min_weight, exclude=args.exclude, booleans=booleans) if args.shortest_path or args.all_paths: if args.shortest_path: paths = g.all_shortest_paths(args.source, args.target) else: paths = g.all_paths(args.source, args.target, args.all_paths) flownum = 0 for flownum, path in enumerate(paths, start=1): print("Flow {0}:".format(flownum)) for stepnum, step in enumerate(path, start=1): print(" Step {0}: {1} -> {2}".format(stepnum, step.source, step.target)) for rule in sorted(step.rules): print(" ", rule) print() if args.limit_flows and flownum >= args.limit_flows: break print() else: # single direct info flow flownum = 0 for flownum, flow in enumerate(g.infoflows(args.source), start=1): print("Flow {0}: {1} -> {2}".format(flownum, flow.source, flow.target)) for rule in sorted(flow.rules): print(" ", rule) print() if args.limit_flows and flownum >= args.limit_flows: break print(flownum, "information flow(s) found.") if args.stats: print("\nGraph statistics:") print(g.get_stats()) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/sesearch000077500000000000000000000273321402045477700147530ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import setools import argparse import sys import logging import signal signal.signal(signal.SIGPIPE, signal.SIG_DFL) parser = argparse.ArgumentParser( description="SELinux policy rule search tool.", epilog="TE/MLS rule searches cannot be mixed with RBAC rule searches.") parser.add_argument("--version", action="version", version=setools.__version__) parser.add_argument("policy", help="Path to the SELinux policy to search.", nargs="?") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra informational messages") parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") rtypes = parser.add_argument_group("TE Rule Types") rtypes.add_argument("-A", action="store_true", help="Search allow and allowxperm rules.") rtypes.add_argument("--allow", action="append_const", const=setools.TERuletype.allow, dest="tertypes", help="Search allow rules.") rtypes.add_argument("--allowxperm", action="append_const", const=setools.TERuletype.allowxperm, dest="tertypes", help="Search allowxperm rules.") rtypes.add_argument("--auditallow", action="append_const", const=setools.TERuletype.auditallow, dest="tertypes", help="Search auditallow rules.") rtypes.add_argument("--auditallowxperm", action="append_const", const=setools.TERuletype.auditallowxperm, dest="tertypes", help="Search auditallowxperm rules.") rtypes.add_argument("--dontaudit", action="append_const", const=setools.TERuletype.dontaudit, dest="tertypes", help="Search dontaudit rules.") rtypes.add_argument("--dontauditxperm", action="append_const", const=setools.TERuletype.dontauditxperm, dest="tertypes", help="Search dontauditxperm rules.") rtypes.add_argument("--neverallow", action="append_const", const=setools.TERuletype.neverallow, dest="tertypes", help="Search neverallow rules.") rtypes.add_argument("--neverallowxperm", action="append_const", const=setools.TERuletype.neverallowxperm, dest="tertypes", help="Search neverallowxperm rules.") rtypes.add_argument("-T", "--type_trans", action="append_const", const=setools.TERuletype.type_transition, dest="tertypes", help="Search type_transition rules.") rtypes.add_argument("--type_change", action="append_const", const=setools.TERuletype.type_change, dest="tertypes", help="Search type_change rules.") rtypes.add_argument("--type_member", action="append_const", const=setools.TERuletype.type_member, dest="tertypes", help="Search type_member rules.") rbacrtypes = parser.add_argument_group("RBAC Rule Types") rbacrtypes.add_argument("--role_allow", action="append_const", const=setools.RBACRuletype.allow, dest="rbacrtypes", help="Search role allow rules.") rbacrtypes.add_argument("--role_trans", action="append_const", const=setools.RBACRuletype.role_transition, dest="rbacrtypes", help="Search role_transition rules.") mlsrtypes = parser.add_argument_group("MLS Rule Types") mlsrtypes.add_argument("--range_trans", action="append_const", const=setools.MLSRuletype.range_transition, dest="mlsrtypes", help="Search range_transition rules.") expr = parser.add_argument_group("Expressions") expr.add_argument("-s", "--source", help="Source type/role of the TE/RBAC rule.") expr.add_argument("-t", "--target", help="Target type/role of the TE/RBAC rule.") expr.add_argument("-c", "--class", dest="tclass", help="Comma separated list of object classes") expr.add_argument("-p", "--perms", metavar="PERMS", help="Comma separated list of permissions.") expr.add_argument("-x", "--xperms", metavar="XPERMS", help="Comma separated list of extended permissions.") expr.add_argument("-D", "--default", help="Default of the rule. (type/role/range transition rules)") expr.add_argument("-b", "--bool", dest="boolean", metavar="BOOL", help="Comma separated list of Booleans in the conditional expression.") opts = parser.add_argument_group("Search options") opts.add_argument("-eb", action="store_true", dest="boolean_equal", help="Match Boolean list exactly instead of matching any listed Boolean.") opts.add_argument("-ep", action="store_true", dest="perms_equal", help="Match permission set exactly instead of matching any listed permission.") opts.add_argument("-ex", action="store_true", dest="xperms_equal", help="Match extended permission set exactly instead of matching any listed " "permission.") opts.add_argument("-ds", action="store_false", dest="source_indirect", help="Match source attributes directly instead of matching member types/roles.") opts.add_argument("-dt", action="store_false", dest="target_indirect", help="Match target attributes directly instead of matching member types/roles.") opts.add_argument("-rs", action="store_true", dest="source_regex", help="Use regular expression matching for the source type/role.") opts.add_argument("-rt", action="store_true", dest="target_regex", help="Use regular expression matching for the target type/role.") opts.add_argument("-rc", action="store_true", dest="tclass_regex", help="Use regular expression matching for the object class.") opts.add_argument("-rd", action="store_true", dest="default_regex", help="Use regular expression matching for the default type/role.") opts.add_argument("-rb", action="store_true", dest="boolean_regex", help="Use regular expression matching for Booleans.") args = parser.parse_args() if args.A: try: args.tertypes.extend([setools.TERuletype.allow, setools.TERuletype.allowxperm]) except AttributeError: args.tertypes = [setools.TERuletype.allow, setools.TERuletype.allowxperm] if not args.tertypes and not args.mlsrtypes and not args.rbacrtypes: parser.error("At least one rule type must be specified.") if args.debug: logging.basicConfig(level=logging.DEBUG, format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') elif args.verbose: logging.basicConfig(level=logging.INFO, format='%(message)s') else: logging.basicConfig(level=logging.WARNING, format='%(message)s') try: p = setools.SELinuxPolicy(args.policy) if args.tertypes: terq = setools.TERuleQuery(p, ruletype=args.tertypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, tclass_regex=args.tclass_regex, perms_equal=args.perms_equal, xperms_equal=args.xperms_equal, default=args.default, default_regex=args.default_regex, boolean_regex=args.boolean_regex, boolean_equal=args.boolean_equal) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: terq.tclass = args.tclass else: terq.tclass = args.tclass.split(",") if args.perms: terq.perms = args.perms.split(",") if args.xperms: # https://github.com/python/mypy/issues/220 terq.xperms = setools.xperm_str_to_tuple_ranges(args.xperms) # type: ignore if args.boolean: if args.boolean_regex: terq.boolean = args.boolean else: if args.policy: terq.boolean = args.boolean.split(",") else: # try to find substitutions for old boolean names terq.boolean = map(setools.policyrep.lookup_boolean_name_sub, args.boolean.split(",")) for te_result in sorted(terq.results()): print(te_result) if args.rbacrtypes: rbacrq = setools.RBACRuleQuery(p, ruletype=args.rbacrtypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, default=args.default, default_regex=args.default_regex, tclass_regex=args.tclass_regex) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: rbacrq.tclass = args.tclass else: rbacrq.tclass = args.tclass.split(",") for rbac_result in sorted(rbacrq.results()): print(rbac_result) if args.mlsrtypes: mlsrq = setools.MLSRuleQuery(p, ruletype=args.mlsrtypes, source=args.source, source_indirect=args.source_indirect, source_regex=args.source_regex, target=args.target, target_indirect=args.target_indirect, target_regex=args.target_regex, tclass_regex=args.tclass_regex, default=args.default) # these are broken out from the above statement to prevent making a list # with an empty string in it (split on empty string) if args.tclass: if args.tclass_regex: mlsrq.tclass = args.tclass else: mlsrq.tclass = args.tclass.split(",") for mls_result in sorted(mlsrq.results()): print(mls_result) except Exception as err: if args.debug: raise else: print(err) sys.exit(1) setools-4.4.0/setools/000077500000000000000000000000001402045477700147115ustar00rootroot00000000000000setools-4.4.0/setools/__init__.py000066400000000000000000000075611402045477700170330ustar00rootroot00000000000000"""The SETools SELinux policy analysis library.""" # Copyright 2014-2015, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # try: import pkg_resources # pylint: disable=no-member __version__ = pkg_resources.get_distribution("setools").version except ImportError: # pragma: no cover __version__ = "unknown" import logging # Python classes for policy representation from .policyrep import SELinuxPolicy, BoundsRuletype, ConstraintRuletype, DefaultRuletype, \ DefaultRangeValue, DefaultValue, FSUseRuletype, HandleUnknown, IbpkeyconRange, MLSRuletype, \ NodeconIPVersion, PolicyTarget, PortconProtocol, RBACRuletype, TERuletype # Policy representation classes for type checking purposes. Few can be instantiated # outside of this library. from .policyrep import AnyConstraint, AnyDefault, AnyRBACRule, AnyTERule, AVRule, AVRuleXperm, \ Boolean, Bounds, Category, Common, Conditional, Constraint, Context, Default, DefaultRange, \ Devicetreecon, FSUse, FileNameTERule, Genfscon, Ibendportcon, Ibpkeycon, InitialSID, \ IoctlSet, Iomemcon, IomemconRange, Ioportcon, IoportconRange, Level, LevelDecl, MLSRule, \ Netifcon, Nodecon, ObjClass, Pcidevicecon, Pirqcon, PolicyCapability, Portcon, PortconRange, \ Range, Role, RoleAllow, RoleTransition, Sensitivity, TERule, TruthTableRow, Type, \ TypeAttribute, User, Validatetrans # Exceptions from . import exception # Base class for policy queries for type checking purposes from .query import PolicyQuery # utility functions from .util import xperm_str_to_tuple_ranges # Component Queries from .boolquery import BoolQuery from .categoryquery import CategoryQuery from .commonquery import CommonQuery from .objclassquery import ObjClassQuery from .polcapquery import PolCapQuery from .rolequery import RoleQuery from .sensitivityquery import SensitivityQuery from .typequery import TypeQuery from .typeattrquery import TypeAttributeQuery from .userquery import UserQuery # Rule Queries from .mlsrulequery import MLSRuleQuery from .rbacrulequery import RBACRuleQuery from .terulequery import TERuleQuery # Constraint queries from .constraintquery import ConstraintQuery # Other queries from .boundsquery import BoundsQuery from .defaultquery import DefaultQuery # In-policy Context Queries from .fsusequery import FSUseQuery from .genfsconquery import GenfsconQuery from .ibendportconquery import IbendportconQuery from .ibpkeyconquery import IbpkeyconQuery from .initsidquery import InitialSIDQuery from .netifconquery import NetifconQuery from .nodeconquery import NodeconQuery from .portconquery import PortconQuery from .ioportconquery import IoportconQuery from .iomemconquery import IomemconQuery from .pirqconquery import PirqconQuery from .pcideviceconquery import PcideviceconQuery from .devicetreeconquery import DevicetreeconQuery # Information Flow Analysis from .infoflow import InfoFlowAnalysis from .permmap import PermissionMap, RuleWeight, Mapping # Domain Transition Analysis from .dta import DomainTransitionAnalysis, DomainEntrypoint, DomainTransition # Policy difference from .diff import PolicyDifference # Policy checker from .checker import PolicyChecker logging.getLogger(__name__).addHandler(logging.NullHandler()) setools-4.4.0/setools/boolquery.py000066400000000000000000000045131402045477700173070ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional from .descriptors import CriteriaDescriptor from .mixins import MatchName from .policyrep import Boolean from .query import PolicyQuery class BoolQuery(MatchName, PolicyQuery): """Query SELinux policy Booleans. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The Boolean name to match. name_regex If true, regular expression matching will be used on the Boolean name. default The default state to match. If this is None, the default state not be matched. """ _default: Optional[bool] = None @property def default(self) -> Optional[bool]: return self._default @default.setter def default(self, value) -> None: if value is None: self._default = None else: self._default = bool(value) def __init__(self, policy, **kwargs) -> None: super(BoolQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Boolean]: """Generator which yields all Booleans matching the criteria.""" self.log.info("Generating Boolean results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Default: {0.default}".format(self)) for boolean in self.policy.bools(): if not self._match_name(boolean): continue if self.default is not None and boolean.state != self.default: continue yield boolean setools-4.4.0/setools/boundsquery.py000066400000000000000000000046621402045477700176530ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .policyrep import Bounds, BoundsRuletype from .query import PolicyQuery from .util import match_regex class BoundsQuery(PolicyQuery): """ Query *bounds statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. """ ruletype = CriteriaSetDescriptor(enum_class=BoundsRuletype) parent = CriteriaDescriptor("parent_regex") parent_regex: bool = False child = CriteriaDescriptor("child_regex") child_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(BoundsQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Bounds]: """Generator which yields all matching *bounds statements.""" self.log.info("Generating bounds results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Parent: {0.parent!r}, regex: {0.parent_regex}".format(self)) self.log.debug("Child: {0.child!r}, regex: {0.child_regex}".format(self)) for b in self.policy.bounds(): if self.ruletype and b.ruletype not in self.ruletype: continue if self.parent and not match_regex( b.parent, self.parent, self.parent_regex): continue if self.child and not match_regex( b.child, self.child, self.child_regex): continue yield b setools-4.4.0/setools/categoryquery.py000066400000000000000000000037341402045477700201750ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .mixins import MatchAlias, MatchName from .policyrep import Category from .query import PolicyQuery class CategoryQuery(MatchAlias, MatchName, PolicyQuery): """ Query MLS Categories Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the category to match. name_regex If true, regular expression matching will be used for matching the name. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. """ def __init__(self, policy, **kwargs) -> None: super(CategoryQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Category]: """Generator which yields all matching categories.""" self.log.info("Generating category results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) for cat in self.policy.categories(): if not self._match_name(cat): continue if not self._match_alias(cat): continue yield cat setools-4.4.0/setools/checker/000077500000000000000000000000001402045477700163155ustar00rootroot00000000000000setools-4.4.0/setools/checker/__init__.py000066400000000000000000000015241402045477700204300ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import assertrbac from . import assertte from . import emptyattr from . import roexec from .checker import PolicyChecker setools-4.4.0/setools/checker/assertrbac.py000066400000000000000000000110111402045477700210120ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # Copyright 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import List, Union from ..exception import InvalidCheckValue from ..policyrep import AnyRBACRule from ..rbacrulequery import RBACRuleQuery from .checkermodule import CheckerModule from .descriptors import ConfigDescriptor, ConfigSetDescriptor SOURCE_OPT = "source" TARGET_OPT = "target" EXEMPT_SRC_OPT = "exempt_source" EXEMPT_TGT_OPT = "exempt_target" EXPECT_SRC_OPT = "expect_source" EXPECT_TGT_OPT = "expect_target" class AssertRBAC(CheckerModule): """Checker module for asserting a RBAC allow rule exists (or not).""" check_type = "assert_rbac" check_config = frozenset((SOURCE_OPT, TARGET_OPT, EXEMPT_SRC_OPT, EXEMPT_TGT_OPT, EXPECT_SRC_OPT, EXPECT_TGT_OPT)) source = ConfigDescriptor("lookup_role") target = ConfigDescriptor("lookup_role") exempt_source = ConfigSetDescriptor("lookup_role", strict=False, expand=True) exempt_target = ConfigSetDescriptor("lookup_role", strict=False, expand=True) expect_source = ConfigSetDescriptor("lookup_role", strict=True, expand=True) expect_target = ConfigSetDescriptor("lookup_role", strict=True, expand=True) def __init__(self, policy, checkname, config) -> None: super().__init__(policy, checkname, config) self.log = logging.getLogger(__name__) self.source = config.get(SOURCE_OPT) self.target = config.get(TARGET_OPT) self.exempt_source = config.get(EXEMPT_SRC_OPT) self.exempt_target = config.get(EXEMPT_TGT_OPT) self.expect_source = config.get(EXPECT_SRC_OPT) self.expect_target = config.get(EXPECT_TGT_OPT) if not any((self.source, self.target)): raise InvalidCheckValue( "At least one of source or target options must be set.") source_exempt_expect_overlap = self.exempt_source & self.expect_source if source_exempt_expect_overlap: self.log.info("Overlap in expect_source and exempt_source: {}". format(", ".join(i.name for i in source_exempt_expect_overlap))) target_exempt_expect_overlap = self.exempt_target & self.expect_target if target_exempt_expect_overlap: self.log.info("Overlap in expect_target and exempt_target: {}". format(", ".join(i.name for i in target_exempt_expect_overlap))) def run(self) -> List: assert any((self.source, self.target)), "AssertRBAC no options set, this is a bug." self.log.info("Checking RBAC allow rule assertion.") query = RBACRuleQuery(self.policy, source=self.source, target=self.target, ruletype=("allow",)) unseen_sources = set(self.expect_source) unseen_targets = set(self.expect_target) failures: List[Union[AnyRBACRule, str]] = [] for rule in sorted(query.results()): srcs = set(rule.source.expand()) tgts = set(rule.target.expand()) unseen_sources -= srcs unseen_targets -= tgts if (srcs - self.expect_source - self.exempt_source) and \ (tgts - self.expect_target - self.exempt_target): self.log_fail(str(rule)) failures.append(rule) else: self.log_ok(str(rule)) for item in unseen_sources: failure = "Expected rule with source \"{}\" not found.".format(item) self.log_fail(failure) failures.append(failure) for item in unseen_targets: failure = "Expected rule with target \"{}\" not found.".format(item) self.log_fail(failure) failures.append(failure) self.log.debug("{} failure(s)".format(failures)) return failures setools-4.4.0/setools/checker/assertte.py000066400000000000000000000120101402045477700205130ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # Copyright 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import List, Union from ..exception import InvalidCheckValue from ..policyrep import AnyTERule from ..terulequery import TERuleQuery from .checkermodule import CheckerModule from .descriptors import ConfigDescriptor, ConfigSetDescriptor, ConfigPermissionSetDescriptor SOURCE_OPT = "source" TARGET_OPT = "target" CLASS_OPT = "tclass" PERMS_OPT = "perms" EXEMPT_SRC_OPT = "exempt_source" EXEMPT_TGT_OPT = "exempt_target" EXPECT_SRC_OPT = "expect_source" EXPECT_TGT_OPT = "expect_target" class AssertTE(CheckerModule): """Checker module for asserting a type enforcement allow rule exists (or not).""" check_type = "assert_te" check_config = frozenset((SOURCE_OPT, TARGET_OPT, CLASS_OPT, PERMS_OPT, EXEMPT_SRC_OPT, EXEMPT_TGT_OPT, EXPECT_SRC_OPT, EXPECT_TGT_OPT)) source = ConfigDescriptor("lookup_type_or_attr") target = ConfigDescriptor("lookup_type_or_attr") tclass = ConfigSetDescriptor("lookup_class", strict=True, expand=False) perms = ConfigPermissionSetDescriptor() exempt_source = ConfigSetDescriptor("lookup_type_or_attr", strict=False, expand=True) exempt_target = ConfigSetDescriptor("lookup_type_or_attr", strict=False, expand=True) expect_source = ConfigSetDescriptor("lookup_type_or_attr", strict=True, expand=True) expect_target = ConfigSetDescriptor("lookup_type_or_attr", strict=True, expand=True) def __init__(self, policy, checkname, config) -> None: super().__init__(policy, checkname, config) self.log = logging.getLogger(__name__) self.source = config.get(SOURCE_OPT) self.target = config.get(TARGET_OPT) self.tclass = config.get(CLASS_OPT) self.perms = config.get(PERMS_OPT) self.exempt_source = config.get(EXEMPT_SRC_OPT) self.exempt_target = config.get(EXEMPT_TGT_OPT) self.expect_source = config.get(EXPECT_SRC_OPT) self.expect_target = config.get(EXPECT_TGT_OPT) if not any((self.source, self.target, self.tclass, self.perms)): raise InvalidCheckValue( "At least one of source, target, tclass, or perms options must be set.") source_exempt_expect_overlap = self.exempt_source & self.expect_source if source_exempt_expect_overlap: self.log.info("Overlap in expect_source and exempt_source: {}". format(", ".join(i.name for i in source_exempt_expect_overlap))) target_exempt_expect_overlap = self.exempt_target & self.expect_target if target_exempt_expect_overlap: self.log.info("Overlap in expect_target and exempt_target: {}". format(", ".join(i.name for i in target_exempt_expect_overlap))) def run(self) -> List: assert any((self.source, self.target, self.tclass, self.perms)), \ "AssertTe no options set, this is a bug." self.log.info("Checking TE allow rule assertion.") query = TERuleQuery(self.policy, source=self.source, target=self.target, tclass=self.tclass, perms=self.perms, ruletype=("allow",)) unseen_sources = set(self.expect_source) unseen_targets = set(self.expect_target) failures: List[Union[AnyTERule, str]] = [] for rule in sorted(query.results()): srcs = set(rule.source.expand()) tgts = set(rule.target.expand()) unseen_sources -= srcs unseen_targets -= tgts if (srcs - self.expect_source - self.exempt_source) and \ (tgts - self.expect_target - self.exempt_target): self.log_fail(str(rule)) failures.append(rule) else: self.log_ok(str(rule)) for item in unseen_sources: failure = "Expected rule with source \"{}\" not found.".format(item) self.log_fail(failure) failures.append(failure) for item in unseen_targets: failure = "Expected rule with target \"{}\" not found.".format(item) self.log_fail(failure) failures.append(failure) self.log.debug("{} failure(s)".format(failures)) return failures setools-4.4.0/setools/checker/checker.py000066400000000000000000000135361402045477700203030ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys import configparser import logging from datetime import datetime, timezone from typing import List from ..exception import InvalidCheckerConfig, InvalidCheckerModule from ..policyrep import SELinuxPolicy from .checkermodule import CHECKER_REGISTRY, CheckerModule from .globalkeys import CHECK_TYPE_KEY SECTION_SEPARATOR = "---------------------------------------------------------\n\n" class PolicyChecker: """Configuration file-driven automated policy analysis checks.""" def __init__(self, policy: SELinuxPolicy, configpath: str) -> None: assert CHECKER_REGISTRY, "No checks are loaded, this is a bug." self.log = logging.getLogger(__name__) self.policy = policy self.checks: List[CheckerModule] = [] self.config = configpath @property def config(self): return self._configpath @config.setter def config(self, configpath: str): self.log.info("Opening policy checker config {}.".format(configpath)) try: with open(configpath, "r") as fd: config = configparser.ConfigParser() config.read_file(fd, source=configpath) except Exception as e: raise InvalidCheckerConfig("Unable to parse checker config {}: {}".format( configpath, e)) from e self.log.info("Validating configuration settings.") checks = [] for checkname, checkconfig in config.items(): if checkname == "DEFAULT": # top level/DEFAULT section is not a check. continue try: check_type = checkconfig[CHECK_TYPE_KEY] except KeyError as e: raise InvalidCheckerModule("{}: Missing {} option.". format(checkname, CHECK_TYPE_KEY)) try: newcheck = CHECKER_REGISTRY[check_type](self.policy, checkname, checkconfig) except KeyError as e: raise InvalidCheckerModule("{}: Unknown policy check type: {}". format(checkname, check_type)) from e checks.append(newcheck) if not checks: raise InvalidCheckerConfig("No checks found in {}.".format(configpath)) self.log.debug("Validated {} checks.".format(len(self.checks))) self.log.info("Successfully opened policy checker config {}.".format(configpath)) self._configpath = configpath self.checks = checks self._config = config def run(self, output=sys.stdout) -> int: """Run all configured checks and print report to the file-like output.""" failures = 0 assert self.checks, "Configuration loaded but no checks configured. This is a bug." output.write(SECTION_SEPARATOR) output.write("Policy check configuration: {}\n".format(self.config)) output.write("Policy being checked: {}\n".format(self.policy)) output.write("Start time: {}\n\n".format(datetime.now(timezone.utc))) result_summary = [] for check in self.checks: check_failures = 0 try: output.write(SECTION_SEPARATOR) output.write("Check name: {}\n\n".format(check.checkname)) if check.desc: output.write("Description: {}\n\n".format(check.desc)) if check.disable: output.write("Check DISABLED. Reason: {}\n\n".format(check.disable)) result_summary.append((check.checkname, "DISABLED ({})".format(check.disable))) self.log.debug("Skipping disabled check {!r}: {}".format(check.checkname, check.disable)) continue self.log.debug("Running check {0!r}, type {1}.".format( check.checkname, check.check_type)) check.output = output check_failures += len(check.run()) output.write("\n") except Exception as e: output.write("Unexpected error: {}. Failing check.\n\n".format(e)) self.log.debug("Exception info", exc_info=e) check_failures += 1 if check_failures: output.write("Check FAILED\n\n") result_summary.append((check.checkname, "FAILED ({} failures)".format( check_failures))) else: output.write("Check PASSED\n\n") result_summary.append((check.checkname, "PASSED")) failures += check_failures output.write(SECTION_SEPARATOR) output.write("Result Summary:\n\n") for checkname, result in result_summary: output.write("{:<39} {}\n".format(checkname, result)) output.write("\n{} failure(s) found.\n\n".format(failures)) output.write("Policy check configuration: {}\n".format(self.config)) output.write("Policy being checked: {}\n".format(self.policy)) output.write("End time: {}\n".format(datetime.now(timezone.utc))) self.log.info("{} failures found in {} checks.".format(failures, len(self.checks))) return failures setools-4.4.0/setools/checker/checkermodule.py000066400000000000000000000110241402045477700214770ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys import logging from abc import ABCMeta, abstractmethod from typing import Dict, FrozenSet, List, Mapping from ..exception import InvalidCheckOption from ..policyrep import SELinuxPolicy from .globalkeys import CHECK_TYPE_KEY, CHECK_DESC_KEY, CHECK_DISABLE, GLOBAL_CONFIG_KEYS CHECKER_REGISTRY: Dict[str, type] = {} __all__ = ['CheckerModule'] class CheckRegistry(ABCMeta): """Checker module registry metaclass. This registers modules in the check registry.""" def __new__(cls, clsname, superclasses, attributedict): check_type = attributedict.get("check_type") check_config = attributedict.get("check_config") if clsname != "CheckerModule": if not isinstance(check_type, str): raise TypeError("Checker module {} does not set a check_type.".format(clsname)) if not isinstance(check_config, frozenset): raise TypeError("Checker module {} does not set a valid check_config.".format( clsname)) if check_type in CHECKER_REGISTRY: existing_check_module = CHECKER_REGISTRY[check_type].__name__ raise TypeError("Checker module {} conflicts with registered check {}".format( clsname, existing_check_module)) classdef = super().__new__(cls, clsname, superclasses, attributedict) if check_type: CHECKER_REGISTRY[check_type] = classdef return classdef class CheckerModule(metaclass=CheckRegistry): """Abstract base class for policy checker modules.""" # The name of the check used in config files. # This must be set by subclasses. check_type: str # The container of valid config keys specific to the check # This is in addition to the common config keys # in the GLOBAL_CONFIG_KEYS above. This must be set by subclasses. # If no additional keys are needed, this should be set to an # empty container. check_config: FrozenSet[str] # T/F log findings that pass the check. log_passing: bool = False # Default output to stdout. output = sys.stdout policy: SELinuxPolicy def __init__(self, policy: SELinuxPolicy, checkname: str, config: Mapping[str, str]) -> None: self.policy = policy self.checkname = checkname # ensure there is a logger available. This should # be replaced with the concrete class' logger self.log = logging.getLogger(__name__) # Check available options are valid valid_options = GLOBAL_CONFIG_KEYS | self.check_config for k in config: if k not in valid_options: raise InvalidCheckOption("{}: Invalid option: {}".format( self.checkname, k)) # Make sure all global config attrs are initialized for this check self.desc = config.get(CHECK_DESC_KEY) self.disable = config.get(CHECK_DISABLE) def log_info(self, msg: str) -> None: """Output an informational message.""" self.output.write(msg) self.output.write("\n") self.log.debug(msg) def log_ok(self, msg: str) -> None: """ Log findings that pass the check. By default these messages are surpressed unless self.log_passing is True. """ if self.log_passing: self.output.write("P * {}\n".format(msg)) self.log.debug("P * {}".format(msg)) def log_fail(self, msg: str) -> None: """Log findings that fail the check.""" self.output.write("{} * {}\n".format("F" if self.log_passing else " ", msg)) self.log.debug("F * {}".format(msg)) @abstractmethod def run(self) -> List: """ Run the configured check on the policy. Return: List of failed items in the check. If the check passes, list is empty. """ pass setools-4.4.0/setools/checker/descriptors.py000066400000000000000000000114621402045477700212340ustar00rootroot00000000000000# Copyright 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import Callable, Union from ..exception import InvalidCheckValue from ..descriptors import CriteriaDescriptor, CriteriaPermissionSetDescriptor class ConfigDescriptor(CriteriaDescriptor): """ Single item configuration option descriptor. Parameter: lookup_function The name of the SELinuxPolicy lookup function, e.g. lookup_type or lookup_boolean. Read-only instance attribute use (obj parameter): checkname The name of the check. policy The instance of SELinuxPolicy """ def __init__(self, lookup_function: Union[Callable, str]) -> None: super().__init__(lookup_function=lookup_function) def __set__(self, obj, value): if not value: self.instances[obj] = None else: try: super().__set__(obj, value.strip()) except ValueError as ex: raise InvalidCheckValue("{}: Invalid {} setting: {}".format( obj.checkname, self.name, ex)) from ex class ConfigSetDescriptor(CriteriaDescriptor): """ Descriptor for a configuration option set. Parameter: lookup_function The name of the SELinuxPolicy lookup function, e.g. lookup_type or lookup_boolean. Keyword Parameters: strict (Bool) If True, all objects must exist in the policy when setting the value. If False, any objects that fail the policy lookup will be dropped instead of raising an exception. The default is True. expand (Bool) If True, each object will be expanded. Default is False. Read-only instance attribute use (obj parameter): checkname The name of the check. log A logger instance. policy The instance of SELinuxPolicy """ def __init__(self, lookup_function: Union[Callable, str], strict: bool = True, expand: bool = False) -> None: super().__init__(lookup_function=lookup_function, default_value=frozenset()) self.strict = strict self.expand = expand def __set__(self, obj, value): if not value: self.instances[obj] = frozenset() else: log = obj.log if callable(self.lookup_function): lookup = self.lookup_function else: lookup = getattr(obj.policy, self.lookup_function) ret = set() for item in (i for i in value.split(" ") if i): try: o = lookup(item) if self.expand: ret.update(o.expand()) else: ret.add(o) except ValueError as e: if self.strict: log.error("Invalid {} item: {}".format(self.name, e)) log.debug("Traceback:", exc_info=e) raise InvalidCheckValue("{}: Invalid {} item: {}".format( obj.checkname, self.name, e)) from e log.info("{}: Invalid {} item: {}".format( obj.checkname, self.name, e)) self.instances[obj] = frozenset(ret) class ConfigPermissionSetDescriptor(CriteriaPermissionSetDescriptor): """ Descriptor for a configuration permissions set. Read-only instance attribute use (obj parameter): checkname The name of the check. policy The instance of SELinuxPolicy tclass If it exists, it will be used to validate the permissions. See validate_perms_any() """ def __init__(self) -> None: super().__init__(default_value=frozenset()) def __set__(self, obj, value): if not value: self.instances[obj] = frozenset() else: try: super().__set__(obj, (v for v in value.split(" ") if v)) except ValueError as ex: raise InvalidCheckValue("{}: Invalid {} setting: {}".format( obj.checkname, self.name, ex)) from ex setools-4.4.0/setools/checker/emptyattr.py000066400000000000000000000065171402045477700207310ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import List from ..exception import InvalidType, InvalidCheckValue from .checkermodule import CheckerModule from .util import config_bool_value ATTR_OPT = "attr" MISSINOK_OPT = "missing_ok" class EmptyTypeAttr(CheckerModule): """Checker module for asserting a type attribute is empty.""" check_type = "empty_typeattr" check_config = frozenset((ATTR_OPT, MISSINOK_OPT)) def __init__(self, policy, checkname, config) -> None: super().__init__(policy, checkname, config) self.log = logging.getLogger(__name__) self._attr = None self._missing_ok = False # this will make the check pass automatically # since the attribute is missing. Only set if # missing_ok is True AND attr is missing. self._pass_by_missing = False self.missing_ok = config.get(MISSINOK_OPT) self.attr = config.get(ATTR_OPT) @property def attr(self): return self._attr @attr.setter def attr(self, value): try: if not value: raise InvalidCheckValue("{}: \"{}\" setting is missing.".format(self.checkname, ATTR_OPT)) self._attr = self.policy.lookup_typeattr(value) self._pass_by_missing = False except InvalidType as e: if not self.missing_ok: raise InvalidCheckValue("{}: attr setting error: {}".format( self.checkname, e)) from e self._attr = value self._pass_by_missing = True @property def missing_ok(self): return self._missing_ok @missing_ok.setter def missing_ok(self, value): self._missing_ok = config_bool_value(value) if self._missing_ok and isinstance(self.attr, str): # attr is only a string if it doesn't exist. self._pass_by_missing = True else: self._pass_by_missing = False def run(self) -> List: self.log.info("Checking type attribute {} is empty.".format(self.attr)) failures = [] if self._pass_by_missing: self.log_info(" {} does not exist.".format(self.attr)) else: self.output.write("Member types of {}:\n".format(self.attr)) types = sorted(self.attr.expand()) if types: for type_ in types: self.log_fail(type_.name) failures.append(type_) else: self.log_ok(" ") self.log.debug("{} failure(s)".format(failures)) return failures setools-4.4.0/setools/checker/globalkeys.py000066400000000000000000000016521402045477700210270ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # This is a separate file to break a circular import. CHECK_TYPE_KEY = "check_type" CHECK_DESC_KEY = "desc" CHECK_DISABLE = "disable" GLOBAL_CONFIG_KEYS = frozenset((CHECK_TYPE_KEY, CHECK_DESC_KEY, CHECK_DISABLE)) setools-4.4.0/setools/checker/roexec.py000066400000000000000000000102311402045477700201510ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from collections import defaultdict from typing import Dict, List, Set from ..policyrep import AnyTERule, Type from ..terulequery import TERuleQuery from .checkermodule import CheckerModule from .descriptors import ConfigSetDescriptor EXEMPT_WRITE = "exempt_write_domain" EXEMPT_EXEC = "exempt_exec_domain" EXEMPT_FILE = "exempt_file" class ReadOnlyExecutables(CheckerModule): """Checker module for asserting all executable files are read-only.""" check_type = "ro_execs" check_config = frozenset((EXEMPT_WRITE, EXEMPT_EXEC, EXEMPT_FILE)) exempt_write_domain = ConfigSetDescriptor("lookup_type_or_attr", strict=False, expand=True) exempt_file = ConfigSetDescriptor("lookup_type_or_attr", strict=False, expand=True) exempt_exec_domain = ConfigSetDescriptor("lookup_type_or_attr", strict=False, expand=True) def __init__(self, policy, checkname, config) -> None: super().__init__(policy, checkname, config) self.log = logging.getLogger(__name__) self.exempt_write_domain = config.get(EXEMPT_WRITE) self.exempt_file = config.get(EXEMPT_FILE) self.exempt_exec_domain = config.get(EXEMPT_EXEC) def _collect_executables(self) -> Dict[Type, Set[AnyTERule]]: self.log.debug("Collecting list of executable file types.") self.log.debug("Ignore exec domains: {!r}".format(self.exempt_exec_domain)) query = TERuleQuery(self.policy, ruletype=("allow",), tclass=("file",), perms=("execute", "execute_no_trans")) collected = defaultdict(set) for rule in query.results(): sources = set(rule.source.expand()) - self.exempt_exec_domain targets = set(rule.target.expand()) - self.exempt_file # ignore rule if source or target is an empty attr if not sources or not targets: self.log.debug("Ignoring execute rule: {}".format(rule)) continue for t in targets: self.log.debug("Determined {} is executable by: {}".format(t, rule)) collected[t].add(rule) return collected def run(self) -> List: self.log.info("Checking executables are read-only.") query = TERuleQuery(self.policy, ruletype=("allow",), tclass=("file",), perms=("write", "append")) executables = self._collect_executables() failures = defaultdict(set) for exec_type in executables.keys(): self.log.debug("Checking if executable type {} is writable.".format(exec_type)) query.target = exec_type for rule in sorted(query.results()): if set(rule.source.expand()) - self.exempt_write_domain: failures[exec_type].add(rule) for exec_type in sorted(failures.keys()): self.output.write("\n------------\n\n") self.output.write("Executable type {} is writable.\n\n".format(exec_type)) self.output.write("Execute rules:\n") for rule in sorted(executables[exec_type]): self.output.write(" * {}\n".format(rule)) self.output.write("\nWrite rules:\n") for rule in sorted(failures[exec_type]): self.log_fail(str(rule)) self.log.debug("{} failure(s)".format(len(failures))) return sorted(failures.keys()) setools-4.4.0/setools/checker/util.py000066400000000000000000000017251402045477700176510ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # def config_bool_value(value) -> bool: """Convert a boolean configuration value.""" if isinstance(value, str): if value and value.strip().lower() in ("yes", "true", "1"): return True return False return bool(value) setools-4.4.0/setools/commonquery.py000066400000000000000000000043121402045477700176410ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .mixins import MatchName, MatchPermission from .policyrep import Common from .query import PolicyQuery class CommonQuery(MatchPermission, MatchName, PolicyQuery): """ Query common permission sets. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the common to match. name_regex If true, regular expression matching will be used for matching the name. perms The permissions to match. perms_equal If true, only commons with permission sets that are equal to the criteria will match. Otherwise, any intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. """ def __init__(self, policy, **kwargs) -> None: super(CommonQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Common]: """Generator which yields all matching commons.""" self.log.info("Generating common results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_perms_debug(self.log) for com in self.policy.commons(): if not self._match_name(com): continue if not self._match_perms(com): continue yield com setools-4.4.0/setools/constraintquery.py000066400000000000000000000131631402045477700205410ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable, Set from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .exception import ConstraintUseError from .mixins import MatchObjClass, MatchPermission from .policyrep import AnyConstraint, ConstraintRuletype from .query import PolicyQuery from .util import match_in_set class ConstraintQuery(MatchObjClass, MatchPermission, PolicyQuery): """ Query constraint rules, (mls)constrain/(mls)validatetrans. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. perms The permission(s) to match. perms_equal If true, the permission set of the rule must exactly match the permissions criteria. If false, any set intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. role The name of the role to match in the constraint expression. role_indirect If true, members of an attribute will be matched rather than the attribute itself. role_regex If true, regular expression matching will be used on the role. type_ The name of the type/attribute to match in the constraint expression. type_indirect If true, members of an attribute will be matched rather than the attribute itself. type_regex If true, regular expression matching will be used on the type/attribute. user The name of the user to match in the constraint expression. user_regex If true, regular expression matching will be used on the user. """ ruletype = CriteriaSetDescriptor(enum_class=ConstraintRuletype) user = CriteriaDescriptor("user_regex", "lookup_user") user_regex: bool = False role = CriteriaDescriptor("role_regex", "lookup_role") role_regex: bool = False role_indirect: bool = True type_ = CriteriaDescriptor("type_regex", "lookup_type_or_attr") type_regex: bool = False type_indirect: bool = True def __init__(self, policy, **kwargs) -> None: super(ConstraintQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def _match_expr(self, expr, criteria, indirect, regex): """ Match roles/types/users in a constraint expression, optionally by expanding the contents of attributes. Parameters: expr The expression to match. criteria The criteria to match. indirect If attributes in the expression should be expanded. regex If regular expression matching should be used. """ if indirect: obj = set() for item in expr: obj.update(item.expand()) else: obj = expr return match_in_set(obj, criteria, regex) def results(self) -> Iterable[AnyConstraint]: """Generator which yields all matching constraints rules.""" self.log.info("Generating constraint results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self._match_object_class_debug(self.log) self._match_perms_debug(self.log) self.log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) self.log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) self.log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) for c in self.policy.constraints(): if self.ruletype: if c.ruletype not in self.ruletype: continue if not self._match_object_class(c): continue try: if not self._match_perms(c): continue except ConstraintUseError: continue if self.role and not self._match_expr( c.expression.roles, self.role, self.role_indirect, self.role_regex): continue if self.type_ and not self._match_expr( c.expression.types, self.type_, self.type_indirect, self.type_regex): continue if self.user and not self._match_expr( c.expression.users, self.user, False, self.user_regex): continue yield c setools-4.4.0/setools/defaultquery.py000066400000000000000000000056411402045477700200030ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import cast, Iterable from .query import PolicyQuery from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchObjClass from .policyrep import AnyDefault, DefaultRange, DefaultRuletype, DefaultValue, DefaultRangeValue class DefaultQuery(MatchObjClass, PolicyQuery): """ Query default_* statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. default The default to base new contexts (e.g. "source" or "target") default_range The range to use on new context, default_range only ("low", "high", "low_high") """ ruletype = CriteriaSetDescriptor(enum_class=DefaultRuletype) default = CriteriaDescriptor(enum_class=DefaultValue) default_range = CriteriaDescriptor(enum_class=DefaultRangeValue) def __init__(self, policy, **kwargs) -> None: super(DefaultQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[AnyDefault]: """Generator which yields all matching default_* statements.""" self.log.info("Generating default_* results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype!r}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}".format(self)) self.log.debug("Range: {0.default_range!r}".format(self)) for d in self.policy.defaults(): if self.ruletype and d.ruletype not in self.ruletype: continue if not self._match_object_class(d): continue if self.default and d.default != self.default: continue if self.default_range: try: if cast(DefaultRange, d).default_range != self.default_range: continue except AttributeError: continue yield d setools-4.4.0/setools/descriptors.py000066400000000000000000000244751402045477700176400ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2016, 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # """ SETools descriptors. These classes override how a class's attributes are get/set/deleted. This is how the @property decorator works. See https://docs.python.org/3/howto/descriptor.html for more details. """ import re from abc import ABC, abstractmethod from collections import defaultdict from collections.abc import Collection from enum import Enum from typing import Any, Callable, MutableMapping, Optional, Union from weakref import WeakKeyDictionary from .util import validate_perms_any # # Query criteria descriptors # # Implementation note: if the name_regex attribute value # is changed the criteria must be reset. # class CriteriaDescriptor: """ Single item criteria descriptor. Keyword Parameters: name_regex The name of instance's regex setting attribute; used as name_regex below. If unset, regular expressions will never be used. lookup_function The name of the SELinuxPolicy lookup function, e.g. lookup_type or lookup_boolean. default_value The default value of the criteria. The default is None. enum_class The class of enumeration which supports a lookup class method. Read-only instance attribute use (obj parameter): policy The instance of SELinuxPolicy name_regex This attribute is read to determine if the criteria should be looked up or compiled into a regex. If the attribute does not exist, False is assumed. """ def __init__(self, name_regex: Optional[str] = None, lookup_function: Optional[Union[Callable, str]] = None, default_value=None, enum_class: Optional[Enum] = None) -> None: assert name_regex or lookup_function or enum_class, \ "A simple attribute should be used if there is no regex, lookup function, or enum." assert not (lookup_function and enum_class), \ "Lookup functions and enum classes are mutually exclusive." self.regex: Optional[str] = name_regex self.default_value = default_value self.lookup_function: Optional[Union[Callable, str]] = lookup_function self.enum_class = enum_class self.name: str = "" # use weak references so instances can be # garbage collected, rather than unnecessarily # kept around due to this descriptor. self.instances: MutableMapping = WeakKeyDictionary() def __set_name__(self, owner, name): self.name = name def __get__(self, obj, objtype=None): if obj is None: return self return self.instances.setdefault(obj, self.default_value) def __set__(self, obj, value): if not value: self.instances[obj] = self.default_value elif self.regex and getattr(obj, self.regex, False): self.instances[obj] = re.compile(value) elif self.lookup_function: if callable(self.lookup_function): lookup = self.lookup_function else: lookup = getattr(obj.policy, self.lookup_function) self.instances[obj] = lookup(value) elif self.enum_class: self.instances[obj] = self.enum_class.lookup(value) else: self.instances[obj] = value class CriteriaSetDescriptor(CriteriaDescriptor): """Descriptor for a set of criteria.""" def __set__(self, obj, value): if not value: self.instances[obj] = self.default_value elif self.regex and getattr(obj, self.regex, False): self.instances[obj] = re.compile(value) elif self.lookup_function: if callable(self.lookup_function): lookup = self.lookup_function else: lookup = getattr(obj.policy, self.lookup_function) self.instances[obj] = frozenset(lookup(v) for v in value) elif self.enum_class: self.instances[obj] = frozenset(self.enum_class.lookup(v) for v in value) else: self.instances[obj] = frozenset(value) class CriteriaPermissionSetDescriptor(CriteriaDescriptor): """ Descriptor for a set of permissions criteria. name_regex The name of instance's regex setting attribute; used as name_regex below. If unset, regular expressions will never be used. default_value The default value of the criteria. The default is None. Read-only instance attribute use (obj parameter): policy The instance of SELinuxPolicy tclass If it exists, it will be used to validate the permissions. See validate_perms_any() tclass_regex If tclass is a regex, the above permission validation will not use tclass: permissions are verified to be in at least one class in the policy but not verified that the permissions are in classes that the regex matches. Assumes False if the attribute doesn't exist. """ def __init__(self, name_regex: Optional[str] = None, default_value=None) -> None: self.regex: Optional[str] = name_regex self.default_value = default_value self.name: str = "" # use weak references so instances can be # garbage collected, rather than unnecessarily # kept around due to this descriptor. self.instances: MutableMapping = WeakKeyDictionary() def __set__(self, obj, value): if not value: self.instances[obj] = self.default_value elif self.regex and getattr(obj, self.regex, False): self.instances[obj] = re.compile(value) else: perms = frozenset(v for v in value) if getattr(obj, "tclass_regex", False): tclass = None else: tclass = getattr(obj, "tclass", None) if tclass and not isinstance(tclass, Collection): tclass = frozenset((tclass,)) validate_perms_any(perms, tclass=tclass, policy=obj.policy) self.instances[obj] = perms # # NetworkX Graph Descriptors # # These descriptors are used to simplify all # of the dictionary use in the NetworkX graph. # class NetworkXGraphEdgeDescriptor(ABC): """ Descriptor abstract base class for NetworkX graph edge attributes. Parameter: name The edge property name Instance class attribute use (obj parameter): G The NetworkX graph source The edge's source node target The edge's target node """ def __init__(self, propname: str) -> None: self.name = propname def __get__(self, obj, objtype=None): if obj is None: return self try: return obj.G[obj.source][obj.target][self.name] except KeyError: raise AttributeError(self.name) @abstractmethod def __set__(self, obj, value): pass @abstractmethod def __delete__(self, obj): pass class EdgeAttrDict(NetworkXGraphEdgeDescriptor): """A descriptor for edge attributes that are dictionaries.""" def __set__(self, obj, value): # None is a special value to initialize the attribute if value is None: obj.G[obj.source][obj.target][self.name] = defaultdict(list) else: raise AttributeError("{0} dictionaries should not be assigned directly". format(self.name)) def __delete__(self, obj): obj.G[obj.source][obj.target][self.name].clear() class EdgeAttrIntMax(NetworkXGraphEdgeDescriptor): """ A descriptor for edge attributes that are non-negative integers that always keep the max assigned value until re-initialized. """ def __set__(self, obj, value): # None is a special value to initialize if value is None: obj.G[obj.source][obj.target][self.name] = 0 else: current_value = obj.G[obj.source][obj.target][self.name] obj.G[obj.source][obj.target][self.name] = max(current_value, value) def __delete__(self, obj): obj.G[obj.source][obj.target][self.name] = 0 class EdgeAttrList(NetworkXGraphEdgeDescriptor): """A descriptor for edge attributes that are lists.""" def __set__(self, obj, value): # None is a special value to initialize if value is None: obj.G[obj.source][obj.target][self.name] = [] else: raise ValueError("{0} lists should not be assigned directly".format(self.name)) def __delete__(self, obj): obj.G[obj.source][obj.target][self.name].clear() # # Permission map descriptors # class PermissionMapDescriptor: """ Descriptor for Permission Map mappings. Parameter: name The map setting name. validator A callable for validating the setting. Instance class attribute use (obj parameter): _perm_map The full permission map. class_ The mapping's object class perm The mapping's permission """ def __init__(self, propname: str, validator: Callable): self.name: str = propname self.validator: Callable = validator def __get__(self, obj, objtype=None): if obj is None: return self return obj._perm_map[obj.class_][obj.perm][self.name] def __set__(self, obj, value): obj._perm_map[obj.class_][obj.perm][self.name] = self.validator(value) def __delete__(self, obj): raise AttributeError setools-4.4.0/setools/devicetreeconquery.py000066400000000000000000000055411402045477700211750ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional from .mixins import MatchContext from .policyrep import Devicetreecon from .query import PolicyQuery class DevicetreeconQuery(MatchContext, PolicyQuery): """ Devicetreecon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: path A single devicetree path. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ path: Optional[str] = None def __init__(self, policy, **kwargs) -> None: super(DevicetreeconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Devicetreecon]: """Generator which yields all matching devicetreecons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Path: {0.path!r}".format(self)) self._match_context_debug(self.log) for devicetreecon in self.policy.devicetreecons(): if self.path and self.path != devicetreecon.path: continue if not self._match_context(devicetreecon.context): continue yield devicetreecon setools-4.4.0/setools/diff/000077500000000000000000000000001402045477700156215ustar00rootroot00000000000000setools-4.4.0/setools/diff/__init__.py000066400000000000000000000062261402045477700177400ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .bool import BooleansDifference from .bounds import BoundsDifference from .commons import CommonDifference from .constraints import ConstraintsDifference from .default import DefaultsDifference from .fsuse import FSUsesDifference from .genfscon import GenfsconsDifference from .ibendportcon import IbendportconsDifference from .ibpkeycon import IbpkeyconsDifference from .initsid import InitialSIDsDifference from .mls import CategoriesDifference, LevelDeclsDifference, SensitivitiesDifference from .mlsrules import MLSRulesDifference from .netifcon import NetifconsDifference from .nodecon import NodeconsDifference from .objclass import ObjClassDifference from .polcap import PolCapsDifference from .portcon import PortconsDifference from .properties import PropertiesDifference from .rbacrules import RBACRulesDifference from .roles import RolesDifference from .terules import TERulesDifference from .typeattr import TypeAttributesDifference from .types import TypesDifference from .users import UsersDifference __all__ = ['PolicyDifference'] class PolicyDifference(BooleansDifference, BoundsDifference, CategoriesDifference, CommonDifference, ConstraintsDifference, DefaultsDifference, FSUsesDifference, GenfsconsDifference, IbendportconsDifference, IbpkeyconsDifference, InitialSIDsDifference, LevelDeclsDifference, MLSRulesDifference, NetifconsDifference, NodeconsDifference, ObjClassDifference, PolCapsDifference, PortconsDifference, PropertiesDifference, RBACRulesDifference, RolesDifference, SensitivitiesDifference, TERulesDifference, TypeAttributesDifference, TypesDifference, UsersDifference): """ Determine the differences from the left policy to the right policy. Parameters: left A policy right A policy """ def _reset_diff(self): """Reset diff results on policy changes.""" for c in PolicyDifference.__bases__: c._reset_diff(self) setools-4.4.0/setools/diff/bool.py000066400000000000000000000060631402045477700171330ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple from ..policyrep import SELinuxPolicy, Boolean from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .typing import SymbolCache _bool_cache: SymbolCache[Boolean] = defaultdict(dict) class ModifiedBoolean(NamedTuple): """Difference details for a modified Boolean.""" added_state: bool removed_state: bool def boolean_wrapper(policy: SELinuxPolicy, boolean: Boolean) -> SymbolWrapper[Boolean]: """ Wrap booleans from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _bool_cache[policy][boolean] except KeyError: b = SymbolWrapper(boolean) _bool_cache[policy][boolean] = b return b class BooleansDifference(Difference): """Determine the difference in type attributes between two policies.""" added_booleans = DiffResultDescriptor("diff_booleans") removed_booleans = DiffResultDescriptor("diff_booleans") modified_booleans = DiffResultDescriptor("diff_booleans") def diff_booleans(self) -> None: """Generate the difference in type attributes between the policies.""" self.log.info("Generating Boolean differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_booleans, self.removed_booleans, matched_booleans = \ self._set_diff( (SymbolWrapper(b) for b in self.left_policy.bools()), (SymbolWrapper(b) for b in self.right_policy.bools())) self.modified_booleans = dict() for left_boolean, right_boolean in matched_booleans: # Criteria for modified booleans # 1. change to default state if left_boolean.state != right_boolean.state: self.modified_booleans[left_boolean] = ModifiedBoolean(right_boolean.state, left_boolean.state) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting Boolean differences") self.added_booleans = None self.removed_booleans = None self.modified_booleans = None setools-4.4.0/setools/diff/bounds.py000066400000000000000000000106471402045477700174750ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import cast, List, NamedTuple, Optional from ..policyrep import Bounds, BoundsRuletype, Type from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper from .types import type_wrapper_factory class ModifiedBounds(NamedTuple): """Difference details for a modified bounds rule.""" rule: Bounds added_bound: Type removed_bound: Type class BoundsDifference(Difference): """Determine the difference in *bounds between two policies.""" added_typebounds = DiffResultDescriptor("diff_typebounds") removed_typebounds = DiffResultDescriptor("diff_typebounds") modified_typebounds = DiffResultDescriptor("diff_typebounds") # Lists of rules for each policy _left_typebounds: Optional[List[Bounds]] = None _right_typebounds: Optional[List[Bounds]] = None def diff_typebounds(self) -> None: """Generate the difference in typebound rules between the policies.""" self.log.info("Generating typebounds differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_typebounds is None or self._right_typebounds is None: self._create_typebound_lists() self.added_typebounds, self.removed_typebounds, matched_typebounds = self._set_diff( (BoundsWrapper(c) for c in cast(List[Bounds], self._left_typebounds)), (BoundsWrapper(c) for c in cast(List[Bounds], self._right_typebounds)), key=lambda b: str(b.child)) self.modified_typebounds = [] for left_bound, right_bound in matched_typebounds: if type_wrapper_factory(left_bound.parent) != type_wrapper_factory(right_bound.parent): self.modified_typebounds.append(ModifiedBounds( left_bound, right_bound.parent, left_bound.parent)) # # Internal functions # def _create_typebound_lists(self) -> None: """Create rule lists for both policies.""" self._left_typebounds = [] for rule in self.left_policy.bounds(): if rule.ruletype == BoundsRuletype.typebounds: self._left_typebounds.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) self._right_typebounds = [] for rule in self.right_policy.bounds(): if rule.ruletype == BoundsRuletype.typebounds: self._right_typebounds.append(rule) else: self.log.error("Unknown rule type: {0} (This is an SETools bug)". format(rule.ruletype)) def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting all *bounds differences") self.added_typebounds = None self.removed_typebounds = None # Sets of rules for each policy self._left_typebounds = None self._right_typebounds = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class BoundsWrapper(Wrapper[Bounds]): # pylint: disable=unsubscriptable-object """Wrap *bounds for diff purposes.""" __slots__ = ("ruletype", "parent", "child") def __init__(self, rule: Bounds) -> None: self.origin = rule self.ruletype = rule.ruletype self.parent = type_wrapper_factory(rule.parent) self.child = type_wrapper_factory(rule.child) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.child == other.child setools-4.4.0/setools/diff/commons.py000066400000000000000000000054241402045477700176530ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple, Set from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper class ModifiedCommon(NamedTuple): """Difference details for a modified common permission set.""" added_perms: Set[str] removed_perms: Set[str] matched_perms: Set[str] class CommonDifference(Difference): """ Determine the difference in common permission sets between two policies. """ added_commons = DiffResultDescriptor("diff_commons") removed_commons = DiffResultDescriptor("diff_commons") modified_commons = DiffResultDescriptor("diff_commons") def diff_commons(self) -> None: """Generate the difference in commons between the policies.""" self.log.info( "Generating common differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_commons, self.removed_commons, matched_commons = self._set_diff( (SymbolWrapper(c) for c in self.left_policy.commons()), (SymbolWrapper(c) for c in self.right_policy.commons())) self.modified_commons = dict() for left_common, right_common in matched_commons: # Criteria for modified commons # 1. change to permissions added_perms, removed_perms, matched_perms = self._set_diff(left_common.perms, right_common.perms, unwrap=False) if added_perms or removed_perms: self.modified_commons[left_common] = ModifiedCommon(added_perms, removed_perms, matched_perms) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting common differences") self.added_commons = None self.removed_commons = None self.modified_commons = None setools-4.4.0/setools/diff/conditional.py000066400000000000000000000037111402045477700205000ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from ..policyrep import Conditional from .difference import Wrapper from .typing import Cache _cond_cache: Cache[Conditional, "ConditionalWrapper"] = defaultdict(dict) def conditional_wrapper_factory(cond: Conditional) -> "ConditionalWrapper": """ Wrap type attributes from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _cond_cache[cond.policy][cond] except KeyError: a = ConditionalWrapper(cond) _cond_cache[cond.policy][cond] = a return a # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class ConditionalWrapper(Wrapper[Conditional]): # pylint: disable=unsubscriptable-object """Wrap conditional policy expressions to allow comparisons by truth table.""" __slots__ = ("truth_table") def __init__(self, cond: Conditional) -> None: self.origin = cond self.truth_table = cond.truth_table() def __hash__(self): return hash(self.origin) def __eq__(self, other): return self.truth_table == other.truth_table def __lt__(self, other): return str(self.origin) < str(other) setools-4.4.0/setools/diff/constraints.py000066400000000000000000000216551402045477700205530ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import FrozenSet, List, Optional, Union from ..policyrep import AnyConstraint, ConstraintRuletype, Role, Type, User from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper from .objclass import class_wrapper_factory from .typing import RuleList class ConstraintsDifference(Difference): """ Determine the difference in constraints between two policies. Since the compiler does not union constraints, there may be multiple constraints with the same ruletype, object class, and permission set, so constraints can only be added or removed, not modified. The constraint expressions are compared only on a basic level. Expressions that are logically equivalent but are structurally different, for example, by associativity, will be considered different. Type and role attributes are also not expanded, so if there are changes to attribute members, it will not be reflected as a difference. """ added_constrains = DiffResultDescriptor("diff_constrains") removed_constrains = DiffResultDescriptor("diff_constrains") added_mlsconstrains = DiffResultDescriptor("diff_mlsconstrains") removed_mlsconstrains = DiffResultDescriptor("diff_mlsconstrains") added_validatetrans = DiffResultDescriptor("diff_validatetrans") removed_validatetrans = DiffResultDescriptor("diff_validatetrans") added_mlsvalidatetrans = DiffResultDescriptor("diff_mlsvalidatetrans") removed_mlsvalidatetrans = DiffResultDescriptor("diff_mlsvalidatetrans") # Lists of rules for each policy _left_constraints: RuleList[ConstraintRuletype, AnyConstraint] = None _right_constraints: RuleList[ConstraintRuletype, AnyConstraint] = None def diff_constrains(self) -> None: """Generate the difference in constraint rules between the policies.""" self.log.info("Generating constraint differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_constraints is None or self._right_constraints is None: self._create_constrain_lists() assert self._left_constraints is not None, "Left constraints didn't load, this a bug." assert self._right_constraints is not None, "Right constraints didn't load, this a bug." self.added_constrains, self.removed_constrains, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_constraints[ConstraintRuletype.constrain]), (ConstraintWrapper(c) for c in self._right_constraints[ConstraintRuletype.constrain])) def diff_mlsconstrains(self) -> None: """Generate the difference in MLS constraint rules between the policies.""" self.log.info( "Generating MLS constraint differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_constraints is None or self._right_constraints is None: self._create_constrain_lists() assert self._left_constraints is not None, "Left constraints didn't load, this a bug." assert self._right_constraints is not None, "Right constraints didn't load, this a bug." self.added_mlsconstrains, self.removed_mlsconstrains, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_constraints[ ConstraintRuletype.mlsconstrain]), (ConstraintWrapper(c) for c in self._right_constraints[ ConstraintRuletype.mlsconstrain])) def diff_validatetrans(self) -> None: """Generate the difference in validatetrans rules between the policies.""" self.log.info( "Generating validatetrans differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_constraints is None or self._right_constraints is None: self._create_constrain_lists() assert self._left_constraints is not None, "Left constraints didn't load, this a bug." assert self._right_constraints is not None, "Right constraints didn't load, this a bug." self.added_validatetrans, self.removed_validatetrans, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_constraints[ ConstraintRuletype.validatetrans]), (ConstraintWrapper(c) for c in self._right_constraints[ ConstraintRuletype.validatetrans])) def diff_mlsvalidatetrans(self) -> None: """Generate the difference in MLS validatetrans rules between the policies.""" self.log.info( "Generating mlsvalidatetrans differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_constraints is None or self._right_constraints is None: self._create_constrain_lists() assert self._left_constraints is not None, "Left constraints didn't load, this a bug." assert self._right_constraints is not None, "Right constraints didn't load, this a bug." self.added_mlsvalidatetrans, self.removed_mlsvalidatetrans, _ = self._set_diff( (ConstraintWrapper(c) for c in self._left_constraints[ ConstraintRuletype.mlsvalidatetrans]), (ConstraintWrapper(c) for c in self._right_constraints[ ConstraintRuletype.mlsvalidatetrans])) # # Internal functions # def _create_constrain_lists(self) -> None: """Create rule lists for both policies.""" self._left_constraints = defaultdict(list) self.log.debug("Building constraint lists from {0.left_policy}".format(self)) for rule in self.left_policy.constraints(): self._left_constraints[rule.ruletype].append(rule) for ruletype, rules in self._left_constraints.items(): self.log.debug("Loaded {0} {1} rules.".format(len(rules), ruletype)) self._right_constraints = defaultdict(list) self.log.debug("Building constraint lists from {0.right_policy}".format(self)) for rule in self.right_policy.constraints(): self._right_constraints[rule.ruletype].append(rule) for ruletype, rules in self._right_constraints.items(): self.log.debug("Loaded {0} {1} rules.".format(len(rules), ruletype)) self.log.debug("Completed building constraint rule lists.") def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting all constraints differences") self.added_constrains = None self.removed_constrains = None self.added_mlsconstrains = None self.removed_mlsconstrains = None self.added_validatetrans = None self.removed_validatetrans = None self.added_mlsvalidatetrans = None self.removed_mlsvalidatetrans = None # Sets of rules for each policy self._left_constraints = None self._right_constraints = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class ConstraintWrapper(Wrapper[AnyConstraint]): # pylint: disable=unsubscriptable-object """Wrap constraints for diff purposes.""" __slots__ = ("ruletype", "tclass", "perms", "expr") def __init__(self, rule: AnyConstraint) -> None: self.origin = rule self.ruletype = rule.ruletype self.tclass = class_wrapper_factory(rule.tclass) try: self.perms: Optional[FrozenSet[str]] = rule.perms except AttributeError: # (mls)validatetrans self.perms = None self.key = hash(rule) self.expr: List[Union[FrozenSet[SymbolWrapper[Union[Role, Type, User]]], str]] = [] for op in rule.expression: if isinstance(op, frozenset): # lists of types/users/roles self.expr.append(frozenset(SymbolWrapper(item) for item in op)) else: # strings in the expression such as u1/r1/t1 or "==" self.expr.append(op) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.tclass == other.tclass and \ self.perms == other.perms and \ self.expr == other.expr setools-4.4.0/setools/diff/context.py000066400000000000000000000041231402045477700176570ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import Optional from ..exception import MLSDisabled from ..policyrep import Context from .difference import Wrapper from .mls import RangeWrapper from .roles import role_wrapper_factory from .types import type_wrapper_factory from .users import user_wrapper_factory # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class ContextWrapper(Wrapper[Context]): # pylint: disable=unsubscriptable-object """Wrap contexts to allow comparisons.""" __slots__ = ("user", "role", "type_", "range_") def __init__(self, ctx: Context) -> None: self.origin = ctx self.user = user_wrapper_factory(ctx.user) self.role = role_wrapper_factory(ctx.role) self.type_ = type_wrapper_factory(ctx.type_) try: self.range_: Optional[RangeWrapper] = RangeWrapper(ctx.range_) except MLSDisabled: self.range_ = None def __hash__(self): return hash(self.origin) def __eq__(self, other): return self.user == other.user and \ self.role == other.role and \ self.type_ == other.type_ and \ self.range_ == other.range_ def __lt__(self, other): return self.user < other.user and \ self.role < other.role and \ self.type_ < other.type_ and \ self.range_ < other.range_ setools-4.4.0/setools/diff/default.py000066400000000000000000000104111402045477700176140ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple, Optional from ..policyrep import Default, DefaultRuletype, DefaultValue, DefaultRangeValue, ObjClass from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper class ModifiedDefault(NamedTuple): """Difference details for a modified default_*.""" rule: Default added_default: Optional[DefaultValue] removed_default: Optional[DefaultValue] added_default_range: Optional[DefaultRangeValue] removed_default_range: Optional[DefaultRangeValue] class DefaultsDifference(Difference): """Determine the difference in default_* between two policies.""" added_defaults = DiffResultDescriptor("diff_defaults") removed_defaults = DiffResultDescriptor("diff_defaults") modified_defaults = DiffResultDescriptor("diff_defaults") def diff_defaults(self) -> None: """Generate the difference in type defaults between the policies.""" self.log.info( "Generating default_* differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_defaults, self.removed_defaults, matched_defaults = self._set_diff( (DefaultWrapper(d) for d in self.left_policy.defaults()), (DefaultWrapper(d) for d in self.right_policy.defaults())) self.modified_defaults = [] for left_default, right_default in matched_defaults: # Criteria for modified defaults # 1. change to default setting # 2. change to default range if left_default.default != right_default.default: removed_default = left_default.default added_default = right_default.default else: removed_default = None added_default = None try: if left_default.default_range != right_default.default_range: removed_default_range = left_default.default_range added_default_range = right_default.default_range else: removed_default_range = None added_default_range = None except AttributeError: removed_default_range = None added_default_range = None if removed_default or removed_default_range: self.modified_defaults.append( ModifiedDefault(left_default, added_default, removed_default, added_default_range, removed_default_range)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting default_* differences") self.added_defaults = None self.removed_defaults = None self.modified_defaults = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class DefaultWrapper(Wrapper[Default]): # pylint: disable=unsubscriptable-object """Wrap default_* to allow comparisons.""" __slots__ = ("ruletype", "tclass") def __init__(self, default: Default) -> None: self.origin = default self.ruletype = default.ruletype self.tclass = SymbolWrapper(default.tclass) self.key = hash(default) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and \ self.tclass == other.tclass setools-4.4.0/setools/diff/descriptors.py000066400000000000000000000032441402045477700205370ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import MutableMapping from weakref import WeakKeyDictionary class DiffResultDescriptor: """Descriptor for managing diff results.""" # @properties could be used instead, but there are so # many result attributes, this will keep the code cleaner. def __init__(self, diff_function: str) -> None: self.diff_function = diff_function # use weak references so instances can be # garbage collected, rather than unnecessarily # kept around due to this descriptor. self.instances: MutableMapping = WeakKeyDictionary() def __get__(self, obj, objtype=None): if obj is None: return self if self.instances.setdefault(obj, None) is None: diff = getattr(obj, self.diff_function) diff() return self.instances[obj] def __set__(self, obj, value): self.instances[obj] = value def __delete__(self, obj): self.instances[obj] = None setools-4.4.0/setools/diff/difference.py000066400000000000000000000140541402045477700202710ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from abc import ABC, abstractmethod from typing import Generic, Iterable, TypeVar from ..policyrep import PolicyObject, PolicySymbol, SELinuxPolicy class Difference: """Base class for all policy differences.""" def __init__(self, left_policy: SELinuxPolicy, right_policy: SELinuxPolicy) -> None: self.log = logging.getLogger(__name__) self.left_policy = left_policy self.right_policy = right_policy # # Policies to compare # @property def left_policy(self): return self._left_policy @left_policy.setter def left_policy(self, policy): self.log.info("Policy diff left policy set to {0}".format(policy)) self._left_policy = policy self._reset_diff() @property def right_policy(self): return self._right_policy @right_policy.setter def right_policy(self, policy): self.log.info("Policy diff right policy set to {0}".format(policy)) self._right_policy = policy self._reset_diff() # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" raise NotImplementedError @staticmethod def _expand_generator(rule_list: Iterable, wrapper_class) -> Iterable: """Generator that yields a wrapped, expanded rule list.""" # this is to delay creating any containers # as long as possible, since rule lists # are typically massive. for unexpanded_rule in rule_list: for expanded_rule in unexpanded_rule.expand(): yield wrapper_class(expanded_rule) @staticmethod def _set_diff(left, right, key=None, unwrap=True): """ Standard diff of two sets. Parameters: left An iterable right An iterable Return: tuple (added, removed, matched) added Set of items in right but not left removed Set of items in left but not right matched Set of items in both left and right. This is in the form of tuples with the matching item from left and right """ left_items = set(left) right_items = set(right) added_items = right_items - left_items removed_items = left_items - right_items # The problem here is the symbol from both policies are # needed to build each tuple in the matched items set. # Using the standard Python set intersection code will only result # in one object. # # This tuple-generating code creates lists from the sets, to sort them. # This should result in all of the symbols lining up. If they don't, # this will break the caller. This should work since there is no remapping. # # This has extra checking to make sure this assertion holds, to fail # instead of giving wrong results. If there is a better way to, # ensure the items match up, please let me know how or submit a patch. matched_items = set() left_matched_items = sorted((left_items - removed_items), key=key) right_matched_items = sorted((right_items - added_items), key=key) assert len(left_matched_items) == len(right_matched_items), \ "Matched items assertion failure (this is an SETools bug), {0} != {1}". \ format(len(left_matched_items), len(right_matched_items)) for left, right in zip(left_matched_items, right_matched_items): assert left == right, \ "Matched items assertion failure (this is an SETools bug), {0} != {1}".format( left, right) matched_items.add((left, right)) if unwrap: return set(i.origin for i in added_items), \ set(i.origin for i in removed_items), \ set((left.origin, right.origin) for (left, right) in matched_items) else: return added_items, removed_items, matched_items T = TypeVar("T", bound=PolicyObject) class Wrapper(ABC, Generic[T]): """Abstract base class for policy object wrappers.""" origin: T key: int __slots__ = ("origin", "key") def __init__(self, symbol: T) -> None: pass def __repr__(self): # pylint: disable=no-member return "<{0.__class__.__name__}(Wrapping {1})>".format(self, repr(self.origin)) @abstractmethod def __hash__(self): pass @abstractmethod def __eq__(self, other): pass @abstractmethod def __lt__(self, other): pass def __ne__(self, other): return not self == other S = TypeVar("S", bound=PolicySymbol) # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class SymbolWrapper(Wrapper[S]): # pylint: disable=unsubscriptable-object """ General wrapper for policy symbols, e.g. types, roles to provide a diff-specific equality operation based on its name. """ name: str __slots__ = ("name",) def __init__(self, symbol: S) -> None: self.origin = symbol self.name = str(symbol) self.key = hash(self.name) def __hash__(self): return self.key def __lt__(self, other): return self.name < other.name def __eq__(self, other): return self.name == other.name setools-4.4.0/setools/diff/fsuse.py000066400000000000000000000063271402045477700173300ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, FSUse from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedFSUse(NamedTuple): """Difference details for a modified fs_use_*.""" rule: FSUse added_context: Context removed_context: Context class FSUsesDifference(Difference): """Determine the difference in fs_use_* rules between two policies.""" added_fs_uses = DiffResultDescriptor("diff_fs_uses") removed_fs_uses = DiffResultDescriptor("diff_fs_uses") modified_fs_uses = DiffResultDescriptor("diff_fs_uses") def diff_fs_uses(self) -> None: """Generate the difference in fs_use rules between the policies.""" self.log.info( "Generating fs_use_* differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_fs_uses, self.removed_fs_uses, matched = self._set_diff( (FSUseWrapper(fs) for fs in self.left_policy.fs_uses()), (FSUseWrapper(fs) for fs in self.right_policy.fs_uses())) self.modified_fs_uses = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to context if ContextWrapper(left_rule.context) != ContextWrapper(right_rule.context): self.modified_fs_uses.append(ModifiedFSUse(left_rule, right_rule.context, left_rule.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting fs_use_* rule differences") self.added_fs_uses = None self.removed_fs_uses = None self.modified_fs_uses = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class FSUseWrapper(Wrapper[FSUse]): # pylint: disable=unsubscriptable-object """Wrap fs_use_* rules to allow set operations.""" __slots__ = ("ruletype", "fs", "context") def __init__(self, rule: FSUse) -> None: self.origin = rule self.ruletype = rule.ruletype self.fs = rule.fs self.context = ContextWrapper(rule.context) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.ruletype == other.ruletype and self.fs == other.fs setools-4.4.0/setools/diff/genfscon.py000066400000000000000000000066001402045477700177770ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, Genfscon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedGenfscon(NamedTuple): """Difference details for a modified genfscons.""" rule: Genfscon added_context: Context removed_context: Context class GenfsconsDifference(Difference): """Determine the difference in genfscon rules between two policies.""" added_genfscons = DiffResultDescriptor("diff_genfscons") removed_genfscons = DiffResultDescriptor("diff_genfscons") modified_genfscons = DiffResultDescriptor("diff_genfscons") def diff_genfscons(self) -> None: """Generate the difference in genfscon rules between the policies.""" self.log.info( "Generating genfscon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_genfscons, self.removed_genfscons, matched = self._set_diff( (GenfsconWrapper(fs) for fs in self.left_policy.genfscons()), (GenfsconWrapper(fs) for fs in self.right_policy.genfscons())) self.modified_genfscons = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to context if ContextWrapper(left_rule.context) != ContextWrapper(right_rule.context): self.modified_genfscons.append(ModifiedGenfscon(left_rule, right_rule.context, left_rule.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting genfscon rule differences") self.added_genfscons = None self.removed_genfscons = None self.modified_genfscons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class GenfsconWrapper(Wrapper[Genfscon]): # pylint: disable=unsubscriptable-object """Wrap genfscon rules to allow set operations.""" __slots__ = ("fs", "path", "filetype", "context") def __init__(self, rule: Genfscon) -> None: self.origin = rule self.fs = rule.fs self.path = rule.path self.filetype = rule.filetype self.context = ContextWrapper(rule.context) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): return self.fs == other.fs and \ self.path == other.path and \ self.filetype == other.filetype setools-4.4.0/setools/diff/ibendportcon.py000066400000000000000000000064621402045477700206710ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, Ibendportcon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedIbendportcon(NamedTuple): """Difference details for a modified ibendportcon.""" rule: Ibendportcon added_context: Context removed_context: Context class IbendportconsDifference(Difference): """Determine the difference in ibendportcons between two policies.""" added_ibendportcons = DiffResultDescriptor("diff_ibendportcons") removed_ibendportcons = DiffResultDescriptor("diff_ibendportcons") modified_ibendportcons = DiffResultDescriptor("diff_ibendportcons") def diff_ibendportcons(self) -> None: """Generate the difference in ibendportcons between the policies.""" self.log.info( "Generating ibendportcon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_ibendportcons, self.removed_ibendportcons, matched_ibendportcons = \ self._set_diff( (IbendportconWrapper(n) for n in self.left_policy.ibendportcons()), (IbendportconWrapper(n) for n in self.right_policy.ibendportcons())) self.modified_ibendportcons = [] for left_ibep, right_ibep in matched_ibendportcons: # Criteria for modified ibendportcons # 1. change to context if ContextWrapper(left_ibep.context) != ContextWrapper(right_ibep.context): self.modified_ibendportcons.append( ModifiedIbendportcon(left_ibep, right_ibep.context, left_ibep.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting ibendportcon differences") self.added_ibendportcons = None self.removed_ibendportcons = None self.modified_ibendportcons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class IbendportconWrapper(Wrapper[Ibendportcon]): # pylint: disable=unsubscriptable-object """Wrap ibendportcon statements for diff purposes.""" __slots__ = ("name", "port") def __init__(self, ocon: Ibendportcon) -> None: self.origin = ocon self.name = ocon.name self.port = ocon.port self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.name == other.name and \ self.port == other.port setools-4.4.0/setools/diff/ibpkeycon.py000066400000000000000000000064771402045477700201740ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, Ibpkeycon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedIbpkeycon(NamedTuple): """Difference details for a modified ibpkeycon.""" rule: Ibpkeycon added_context: Context removed_context: Context class IbpkeyconsDifference(Difference): """Determine the difference in ibpkeycons between two policies.""" added_ibpkeycons = DiffResultDescriptor("diff_ibpkeycons") removed_ibpkeycons = DiffResultDescriptor("diff_ibpkeycons") modified_ibpkeycons = DiffResultDescriptor("diff_ibpkeycons") def diff_ibpkeycons(self) -> None: """Generate the difference in ibpkeycons between the policies.""" self.log.info( "Generating ibpkeycon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_ibpkeycons, self.removed_ibpkeycons, matched_ibpkeycons = \ self._set_diff( (IbpkeyconWrapper(n) for n in self.left_policy.ibpkeycons()), (IbpkeyconWrapper(n) for n in self.right_policy.ibpkeycons())) self.modified_ibpkeycons = [] for left_ibpkey, right_ibpkey in matched_ibpkeycons: # Criteria for modified ibpkeycons # 1. change to context if ContextWrapper(left_ibpkey.context) != ContextWrapper(right_ibpkey.context): self.modified_ibpkeycons.append( ModifiedIbpkeycon(left_ibpkey, right_ibpkey.context, left_ibpkey.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting ibpkeycon differences") self.added_ibpkeycons = None self.removed_ibpkeycons = None self.modified_ibpkeycons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class IbpkeyconWrapper(Wrapper[Ibpkeycon]): # pylint: disable=unsubscriptable-object """Wrap ibpkeycon statements for diff purposes.""" __slots__ = ("subnet_prefix", "low", "high") def __init__(self, ocon: Ibpkeycon) -> None: self.origin = ocon self.subnet_prefix = ocon.subnet_prefix self.low, self.high = ocon.pkeys self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.subnet_prefix == other.subnet_prefix and \ self.low == other.low and \ self.high == other.high setools-4.4.0/setools/diff/initsid.py000066400000000000000000000051161402045477700176410ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper class ModifiedInitialSID(NamedTuple): """Difference details for a modified initial SID.""" added_context: Context removed_context: Context class InitialSIDsDifference(Difference): """Determine the difference in initsids between two policies.""" added_initialsids = DiffResultDescriptor("diff_initialsids") removed_initialsids = DiffResultDescriptor("diff_initialsids") modified_initialsids = DiffResultDescriptor("diff_initialsids") def diff_initialsids(self) -> None: """Generate the difference in initial SIDs between the policies.""" self.log.info("Generating initial SID differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_initialsids, self.removed_initialsids, matched_initialsids = self._set_diff( (SymbolWrapper(i) for i in self.left_policy.initialsids()), (SymbolWrapper(i) for i in self.right_policy.initialsids())) self.modified_initialsids = dict() for left_initialsid, right_initialsid in matched_initialsids: # Criteria for modified initialsids # 1. change to context if ContextWrapper(left_initialsid.context) != ContextWrapper(right_initialsid.context): self.modified_initialsids[left_initialsid] = ModifiedInitialSID( right_initialsid.context, left_initialsid.context) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting initialsid differences") self.added_initialsids = None self.removed_initialsids = None self.modified_initialsids = None setools-4.4.0/setools/diff/mls.py000066400000000000000000000255141402045477700167750ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple, Set from ..policyrep import Category, Level, LevelDecl, Range, Sensitivity from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper, Wrapper from .typing import SymbolCache _cats_cache: SymbolCache[Category] = defaultdict(dict) _sens_cache: SymbolCache[Sensitivity] = defaultdict(dict) class ModifiedCategory(NamedTuple): """Difference details for a modified category.""" added_aliases: Set[str] removed_aliases: Set[str] matched_aliases: Set[str] class ModifiedSensitivity(NamedTuple): """Difference details for a modified sensitivity.""" added_aliases: Set[str] removed_aliases: Set[str] matched_aliases: Set[str] class ModifiedLevelDecl(NamedTuple): """Difference details for a modified level declaration.""" level: LevelDecl added_categories: Set[Category] removed_categories: Set[Category] matched_categories: Set[Category] def category_wrapper_factory(category: Category) -> SymbolWrapper[Category]: """ Wrap category from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _cats_cache[category.policy][category] except KeyError: c = SymbolWrapper(category) _cats_cache[category.policy][category] = c return c def sensitivity_wrapper_factory(sensitivity: Sensitivity) -> SymbolWrapper[Sensitivity]: """ Wrap sensitivity from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _sens_cache[sensitivity.policy][sensitivity] except KeyError: c = SymbolWrapper(sensitivity) _sens_cache[sensitivity.policy][sensitivity] = c return c class CategoriesDifference(Difference): """Determine the difference in categories between two policies.""" added_categories = DiffResultDescriptor("diff_categories") removed_categories = DiffResultDescriptor("diff_categories") modified_categories = DiffResultDescriptor("diff_categories") def diff_categories(self) -> None: """Generate the difference in categories between the policies.""" self.log.info( "Generating category differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_categories, self.removed_categories, matched_categories = self._set_diff( (category_wrapper_factory(c) for c in self.left_policy.categories()), (category_wrapper_factory(c) for c in self.right_policy.categories())) self.modified_categories = dict() for left_category, right_category in matched_categories: # Criteria for modified categories # 1. change to aliases added_aliases, removed_aliases, matched_aliases = self._set_diff( left_category.aliases(), right_category.aliases(), unwrap=False) if added_aliases or removed_aliases: self.modified_categories[left_category] = ModifiedCategory(added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting category differences") self.added_categories = None self.removed_categories = None self.modified_categories = None class SensitivitiesDifference(Difference): """Determine the difference in sensitivities between two policies.""" added_sensitivities = DiffResultDescriptor("diff_sensitivities") removed_sensitivities = DiffResultDescriptor("diff_sensitivities") modified_sensitivities = DiffResultDescriptor("diff_sensitivities") def diff_sensitivities(self) -> None: """Generate the difference in sensitivities between the policies.""" self.log.info( "Generating sensitivity differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_sensitivities, self.removed_sensitivities, matched_sensitivities = \ self._set_diff( (sensitivity_wrapper_factory(s) for s in self.left_policy.sensitivities()), (sensitivity_wrapper_factory(s) for s in self.right_policy.sensitivities())) self.modified_sensitivities = dict() for left_sens, right_sens in matched_sensitivities: # Criteria for modified sensitivities # 1. change to aliases added_aliases, removed_aliases, matched_aliases = self._set_diff( left_sens.aliases(), right_sens.aliases(), unwrap=False) if added_aliases or removed_aliases: self.modified_sensitivities[left_sens] = ModifiedSensitivity(added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting sensitivity differences") self.added_sensitivities = None self.removed_sensitivities = None self.modified_sensitivities = None class LevelDeclsDifference(Difference): """Determine the difference in levels between two policies.""" added_levels = DiffResultDescriptor("diff_levels") removed_levels = DiffResultDescriptor("diff_levels") modified_levels = DiffResultDescriptor("diff_levels") def diff_levels(self) -> None: """Generate the difference in levels between the policies.""" self.log.info( "Generating level decl differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_levels, self.removed_levels, matched_levels = \ self._set_diff( (LevelDeclWrapper(s) for s in self.left_policy.levels()), (LevelDeclWrapper(s) for s in self.right_policy.levels())) self.modified_levels = [] for left_level, right_level in matched_levels: # Criteria for modified levels # 1. change to allowed categories added_categories, removed_categories, matched_categories = self._set_diff( (category_wrapper_factory(c) for c in left_level.categories()), (category_wrapper_factory(c) for c in right_level.categories())) if added_categories or removed_categories: self.modified_levels.append(ModifiedLevelDecl( left_level, added_categories, removed_categories, matched_categories)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting sensitivity differences") self.added_levels = None self.removed_levels = None self.modified_levels = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class LevelDeclWrapper(Wrapper[LevelDecl]): # pylint: disable=unsubscriptable-object """Wrap level declarations to allow comparisons.""" __slots__ = ("sensitivity",) def __init__(self, level: LevelDecl) -> None: self.origin = level self.sensitivity = sensitivity_wrapper_factory(level.sensitivity) self.key = hash(level) def __hash__(self): return self.key def __eq__(self, other): # non-MLS policies have no level declarations so there # should be no AttributeError possiblity here return self.sensitivity == other.sensitivity def __lt__(self, other): return self.sensitivity < other.sensitivity # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class LevelWrapper(Wrapper[Level]): # pylint: disable=unsubscriptable-object """Wrap levels to allow comparisons.""" __slots__ = ("sensitivity", "categories") def __init__(self, level: Level) -> None: self.origin = level self.sensitivity = sensitivity_wrapper_factory(level.sensitivity) self.categories = set(category_wrapper_factory(c) for c in level.categories()) def __hash__(self): return hash(self.origin) def __eq__(self, other): try: return self.sensitivity == other.sensitivity and \ self.categories == other.categories except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False def __lt__(self, other): try: return self.sensitivity < other.sensitivity and \ self.categories < other.categories except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class RangeWrapper(Wrapper[Range]): # pylint: disable=unsubscriptable-object """ Wrap ranges to allow comparisons. This only compares the low and high levels of the range. It does not detect additions/removals/modifications to levels between the low and high levels of the range. """ __slots__ = ("low", "high") def __init__(self, range_: Range) -> None: self.origin = range_ self.low = LevelWrapper(range_.low) self.high = LevelWrapper(range_.high) def __hash__(self): return hash(self.origin) def __eq__(self, other): try: return self.low == other.low and \ self.high == other.high except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False def __lt__(self, other): try: return self.low < other.low and \ self.high < other.high except AttributeError: # comparing an MLS policy to non-MLS policy will result in # other being None return False setools-4.4.0/setools/diff/mlsrules.py000066400000000000000000000124211402045477700200410ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple from ..policyrep import MLSRule, MLSRuletype, Range from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper from .mls import RangeWrapper from .objclass import class_wrapper_factory from .types import type_or_attr_wrapper_factory from .typing import RuleList class ModifiedMLSRule(NamedTuple): """Difference details for a modified MLS rule.""" rule: MLSRule added_default: Range removed_default: Range class MLSRulesDifference(Difference): """Determine the difference in MLS rules between two policies.""" added_range_transitions = DiffResultDescriptor("diff_range_transitions") removed_range_transitions = DiffResultDescriptor("diff_range_transitions") modified_range_transitions = DiffResultDescriptor("diff_range_transitions") # Lists of rules for each policy _left_mls_rules: RuleList[MLSRuletype, MLSRule] = None _right_mls_rules: RuleList[MLSRuletype, MLSRule] = None def diff_range_transitions(self) -> None: """Generate the difference in range_transition rules between the policies.""" self.log.info( "Generating range_transition differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_mls_rules is None or self._right_mls_rules is None: self._create_mls_rule_lists() assert self._left_mls_rules is not None, "Left MLS rules did not load, this is a bug." assert self._right_mls_rules is not None, "Right MLS rules did not load, this is a bug." added, removed, matched = self._set_diff( self._expand_generator(self._left_mls_rules[MLSRuletype.range_transition], MLSRuleWrapper), self._expand_generator(self._right_mls_rules[MLSRuletype.range_transition], MLSRuleWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default range if RangeWrapper(left_rule.default) != RangeWrapper(right_rule.default): modified.append(ModifiedMLSRule(left_rule, right_rule.default, left_rule.default)) self.added_range_transitions = added self.removed_range_transitions = removed self.modified_range_transitions = modified # # Internal functions # def _create_mls_rule_lists(self) -> None: """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self._left_mls_rules = defaultdict(list) self.log.debug("Building MLS rule lists from {0.left_policy}".format(self)) for rule in self.left_policy.mlsrules(): self._left_mls_rules[rule.ruletype].append(rule) self._right_mls_rules = defaultdict(list) self.log.debug("Building MLS rule lists from {0.right_policy}".format(self)) for rule in self.right_policy.mlsrules(): self._right_mls_rules[rule.ruletype].append(rule) self.log.debug("Completed building MLS rule lists.") def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting MLS rule differences") self.added_range_transitions = None self.removed_range_transitions = None self.modified_range_transitions = None # Sets of rules for each policy self._left_mls_rules = None self._right_mls_rules = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class MLSRuleWrapper(Wrapper[MLSRule]): # pylint: disable=unsubscriptable-object """Wrap MLS rules to allow set operations.""" __slots__ = ("ruletype", "source", "target", "tclass") def __init__(self, rule: MLSRule) -> None: self.origin = rule self.source = type_or_attr_wrapper_factory(rule.source) self.target = type_or_attr_wrapper_factory(rule.target) self.tclass = class_wrapper_factory(rule.tclass) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because MLSRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass setools-4.4.0/setools/diff/netifcon.py000066400000000000000000000074301402045477700200040ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple, Optional from ..policyrep import Context, Netifcon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedNetifcon(NamedTuple): """Difference details for a modified netifcon.""" rule: Netifcon added_context: Optional[Context] removed_context: Optional[Context] added_packet: Optional[Context] removed_packet: Optional[Context] class NetifconsDifference(Difference): """Determine the difference in netifcons between two policies.""" added_netifcons = DiffResultDescriptor("diff_netifcons") removed_netifcons = DiffResultDescriptor("diff_netifcons") modified_netifcons = DiffResultDescriptor("diff_netifcons") def diff_netifcons(self) -> None: """Generate the difference in netifcons between the policies.""" self.log.info("Generating netifcon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_netifcons, self.removed_netifcons, matched_netifcons = self._set_diff( (NetifconWrapper(n) for n in self.left_policy.netifcons()), (NetifconWrapper(n) for n in self.right_policy.netifcons())) self.modified_netifcons = [] for left_netifcon, right_netifcon in matched_netifcons: # Criteria for modified netifcons # 1. change to context # 2. change to packet context if ContextWrapper(left_netifcon.context) != ContextWrapper(right_netifcon.context): removed_context = left_netifcon.context added_context = right_netifcon.context else: removed_context = None added_context = None if ContextWrapper(left_netifcon.packet) != ContextWrapper(right_netifcon.packet): removed_packet = left_netifcon.packet added_packet = right_netifcon.packet else: removed_packet = None added_packet = None if removed_context or removed_packet: self.modified_netifcons.append(ModifiedNetifcon( left_netifcon, added_context, removed_context, added_packet, removed_packet)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting netifcon differences") self.added_netifcons = None self.removed_netifcons = None self.modified_netifcons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class NetifconWrapper(Wrapper[Netifcon]): # pylint: disable=unsubscriptable-object """Wrap netifcon statements for diff purposes.""" __slots__ = ("netif") def __init__(self, ocon: Netifcon) -> None: self.origin = ocon self.netif = ocon.netif self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.netif < other.netif def __eq__(self, other): return self.netif == other.netif setools-4.4.0/setools/diff/nodecon.py000066400000000000000000000064761402045477700176350ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2017, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, Nodecon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedNodecon(NamedTuple): """Difference details for a modified netifcon.""" rule: Nodecon added_context: Context removed_context: Context class NodeconsDifference(Difference): """Determine the difference in nodecons between two policies.""" added_nodecons = DiffResultDescriptor("diff_nodecons") removed_nodecons = DiffResultDescriptor("diff_nodecons") modified_nodecons = DiffResultDescriptor("diff_nodecons") def diff_nodecons(self) -> None: """Generate the difference in nodecons between the policies.""" self.log.info("Generating nodecon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_nodecons, self.removed_nodecons, matched_nodecons = self._set_diff( (NodeconWrapper(n) for n in self.left_policy.nodecons()), (NodeconWrapper(n) for n in self.right_policy.nodecons())) self.modified_nodecons = [] for left_nodecon, right_nodecon in matched_nodecons: # Criteria for modified nodecons # 1. change to context if ContextWrapper(left_nodecon.context) != ContextWrapper(right_nodecon.context): self.modified_nodecons.append(ModifiedNodecon(left_nodecon, right_nodecon.context, left_nodecon.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting nodecon differences") self.added_nodecons = None self.removed_nodecons = None self.modified_nodecons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class NodeconWrapper(Wrapper[Nodecon]): # pylint: disable=unsubscriptable-object """Wrap nodecon statements for diff purposes.""" __slots__ = ("ip_version", "network") def __init__(self, ocon: Nodecon) -> None: self.origin = ocon self.ip_version = ocon.ip_version self.network = ocon.network self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.ip_version == other.ip_version and \ self.network == other.network setools-4.4.0/setools/diff/objclass.py000066400000000000000000000073211402045477700177760ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from contextlib import suppress from typing import NamedTuple, Set from ..exception import NoCommon from ..policyrep import ObjClass from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .typing import SymbolCache _class_cache: SymbolCache[ObjClass] = defaultdict(dict) class ModifiedObjClass(NamedTuple): """Difference details for a modified object class.""" added_perms: Set[str] removed_perms: Set[str] matched_perms: Set[str] def class_wrapper_factory(class_: ObjClass) -> SymbolWrapper[ObjClass]: """ Wrap class from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _class_cache[class_.policy][class_] except KeyError: c = SymbolWrapper(class_) _class_cache[class_.policy][class_] = c return c class ObjClassDifference(Difference): """ Determine the difference in object classes between two policies. """ added_classes = DiffResultDescriptor("diff_classes") removed_classes = DiffResultDescriptor("diff_classes") modified_classes = DiffResultDescriptor("diff_classes") def diff_classes(self) -> None: """Generate the difference in object classes between the policies.""" self.log.info( "Generating class differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_classes, self.removed_classes, matched_classes = self._set_diff( (SymbolWrapper(c) for c in self.left_policy.classes()), (SymbolWrapper(c) for c in self.right_policy.classes())) self.modified_classes = dict() for left_class, right_class in matched_classes: # Criteria for modified classes # 1. change to permissions (inherited common is expanded) left_perms = left_class.perms with suppress(NoCommon): left_perms |= left_class.common.perms right_perms = right_class.perms with suppress(NoCommon): right_perms |= right_class.common.perms added_perms, removed_perms, matched_perms = self._set_diff(left_perms, right_perms, unwrap=False) if added_perms or removed_perms: self.modified_classes[left_class] = ModifiedObjClass(added_perms, removed_perms, matched_perms) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting object class differences") self.added_classes = None self.removed_classes = None self.modified_classes = None setools-4.4.0/setools/diff/polcap.py000066400000000000000000000033361402045477700174560ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper class PolCapsDifference(Difference): """Determine the difference in polcaps between two policies.""" added_polcaps = DiffResultDescriptor("diff_polcaps") removed_polcaps = DiffResultDescriptor("diff_polcaps") def diff_polcaps(self) -> None: """Generate the difference in polcaps between the policies.""" self.log.info("Generating policy cap differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_polcaps, self.removed_polcaps, _ = self._set_diff( (SymbolWrapper(n) for n in self.left_policy.polcaps()), (SymbolWrapper(n) for n in self.right_policy.polcaps())) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting policy capability differences") self.added_polcaps = None self.removed_polcaps = None setools-4.4.0/setools/diff/portcon.py000066400000000000000000000064511402045477700176650ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple from ..policyrep import Context, Portcon from .context import ContextWrapper from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper class ModifiedPortcon(NamedTuple): """Difference details for a modified portcon.""" rule: Portcon added_context: Context removed_context: Context class PortconsDifference(Difference): """Determine the difference in portcons between two policies.""" added_portcons = DiffResultDescriptor("diff_portcons") removed_portcons = DiffResultDescriptor("diff_portcons") modified_portcons = DiffResultDescriptor("diff_portcons") def diff_portcons(self) -> None: """Generate the difference in portcons between the policies.""" self.log.info("Generating portcon differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_portcons, self.removed_portcons, matched_portcons = self._set_diff( (PortconWrapper(n) for n in self.left_policy.portcons()), (PortconWrapper(n) for n in self.right_policy.portcons())) self.modified_portcons = [] for left_portcon, right_portcon in matched_portcons: # Criteria for modified portcons # 1. change to context if ContextWrapper(left_portcon.context) != ContextWrapper(right_portcon.context): self.modified_portcons.append(ModifiedPortcon(left_portcon, right_portcon.context, left_portcon.context)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting portcon differences") self.added_portcons = None self.removed_portcons = None self.modified_portcons = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class PortconWrapper(Wrapper[Portcon]): # pylint: disable=unsubscriptable-object """Wrap portcon statements for diff purposes.""" __slots__ = ("protocol", "low", "high") def __init__(self, ocon: Portcon) -> None: self.origin = ocon self.protocol = ocon.protocol self.low, self.high = ocon.ports self.key = hash(ocon) def __hash__(self): return self.key def __lt__(self, other): return self.origin < other.origin def __eq__(self, other): return self.protocol == other.protocol and \ self.low == other.low and \ self.high == other.high setools-4.4.0/setools/diff/properties.py000066400000000000000000000046311402045477700203730ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import NamedTuple, Union from ..policyrep import PolicyEnum from .descriptors import DiffResultDescriptor from .difference import Difference class ModifiedProperty(NamedTuple): """Difference details for a modified policy property.""" property: str added: Union[PolicyEnum, bool, int] removed: Union[PolicyEnum, bool, int] class PropertiesDifference(Difference): """ Determine the difference in policy properties (unknown permissions, MLS, etc.) between two policies. """ modified_properties = DiffResultDescriptor("diff_properties") def diff_properties(self) -> None: self.modified_properties = [] if self.left_policy.handle_unknown != self.right_policy.handle_unknown: self.modified_properties.append( ModifiedProperty("handle_unknown", self.right_policy.handle_unknown, self.left_policy.handle_unknown)) if self.left_policy.mls != self.right_policy.mls: self.modified_properties.append( ModifiedProperty("MLS", self.right_policy.mls, self.left_policy.mls)) if self.left_policy.version != self.right_policy.version: self.modified_properties.append( ModifiedProperty("version", self.right_policy.version, self.left_policy.version)) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting property differences") self.modified_properties = None setools-4.4.0/setools/diff/rbacrules.py000066400000000000000000000163371402045477700201670ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple from ..policyrep import AnyRBACRule, RBACRuletype, Role, RoleAllow, RoleTransition from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper from .objclass import class_wrapper_factory from .roles import role_wrapper_factory from .types import type_or_attr_wrapper_factory from .typing import RuleList class ModifiedRBACRule(NamedTuple): """Difference details for a modified RBAC rule.""" rule: AnyRBACRule added_default: Role removed_default: Role class RBACRulesDifference(Difference): """Determine the difference in RBAC rules between two policies.""" added_role_allows = DiffResultDescriptor("diff_role_allows") removed_role_allows = DiffResultDescriptor("diff_role_allows") # role allows cannot be modified, only added/removed added_role_transitions = DiffResultDescriptor("diff_role_transitions") removed_role_transitions = DiffResultDescriptor("diff_role_transitions") modified_role_transitions = DiffResultDescriptor("diff_role_transitions") # Lists of rules for each policy _left_rbac_rules: RuleList[RBACRuletype, AnyRBACRule] = None _right_rbac_rules: RuleList[RBACRuletype, AnyRBACRule] = None def diff_role_allows(self) -> None: """Generate the difference in role allow rules between the policies.""" self.log.info( "Generating role allow differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_rbac_rules is None or self._right_rbac_rules is None: self._create_rbac_rule_lists() assert self._left_rbac_rules is not None, "Left RBAC rules didn't load, this a bug." assert self._right_rbac_rules is not None, "Right RBAC rules didn't load, this a bug." self.added_role_allows, self.removed_role_allows, _ = self._set_diff( self._expand_generator(self._left_rbac_rules[RBACRuletype.allow], RoleAllowWrapper), self._expand_generator(self._right_rbac_rules[RBACRuletype.allow], RoleAllowWrapper)) def diff_role_transitions(self) -> None: """Generate the difference in role_transition rules between the policies.""" self.log.info( "Generating role_transition differences from {0.left_policy} to {0.right_policy}". format(self)) if self._left_rbac_rules is None or self._right_rbac_rules is None: self._create_rbac_rule_lists() assert self._left_rbac_rules is not None, "Left RBAC rules didn't load, this a bug." assert self._right_rbac_rules is not None, "Right RBAC rules didn't load, this a bug." added, removed, matched = self._set_diff( self._expand_generator(self._left_rbac_rules[RBACRuletype.role_transition], RoleTransitionWrapper), self._expand_generator(self._right_rbac_rules[RBACRuletype.role_transition], RoleTransitionWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default role if role_wrapper_factory(left_rule.default) != role_wrapper_factory(right_rule.default): modified.append(ModifiedRBACRule(left_rule, right_rule.default, left_rule.default)) self.added_role_transitions = added self.removed_role_transitions = removed self.modified_role_transitions = modified # # Internal functions # def _create_rbac_rule_lists(self) -> None: """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self._left_rbac_rules = defaultdict(list) self.log.debug("Building RBAC rule lists from {0.left_policy}".format(self)) for rule in self.left_policy.rbacrules(): self._left_rbac_rules[rule.ruletype].append(rule) self._right_rbac_rules = defaultdict(list) self.log.debug("Building RBAC rule lists from {0.right_policy}".format(self)) for rule in self.right_policy.rbacrules(): self._right_rbac_rules[rule.ruletype].append(rule) self.log.debug("Completed building RBAC rule lists.") def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting RBAC rule differences") self.added_role_allows = None self.removed_role_allows = None self.added_role_transitions = None self.removed_role_transitions = None self.modified_role_transitions = None # Sets of rules for each policy self._left_rbac_rules = None self._right_rbac_rules = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class RoleAllowWrapper(Wrapper[RoleAllow]): # pylint: disable=unsubscriptable-object """Wrap role allow rules to allow set operations.""" __slots__ = ("source", "target") def __init__(self, rule: RoleAllow) -> None: self.origin = rule self.source = role_wrapper_factory(rule.source) self.target = role_wrapper_factory(rule.target) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because RBACRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and self.target == other.target # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class RoleTransitionWrapper(Wrapper[RoleTransition]): # pylint: disable=unsubscriptable-object """Wrap role_transition rules to allow set operations.""" __slots__ = ("source", "target", "tclass") def __init__(self, rule: RoleTransition) -> None: self.origin = rule self.source = role_wrapper_factory(rule.source) self.target = type_or_attr_wrapper_factory(rule.target) self.tclass = class_wrapper_factory(rule.tclass) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because RBACRuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass setools-4.4.0/setools/diff/roles.py000066400000000000000000000064431402045477700173260ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple, Set from ..policyrep import Role, Type from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .typing import SymbolCache from .types import type_wrapper_factory _roles_cache: SymbolCache[Role] = defaultdict(dict) class ModifiedRole(NamedTuple): """Difference details for a modified role.""" added_types: Set[Type] removed_types: Set[Type] matched_types: Set[Type] def role_wrapper_factory(role: Role) -> SymbolWrapper[Role]: """ Wrap roles from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _roles_cache[role.policy][role] except KeyError: r = SymbolWrapper(role) _roles_cache[role.policy][role] = r return r class RolesDifference(Difference): """Determine the difference in roles between two policies.""" added_roles = DiffResultDescriptor("diff_roles") removed_roles = DiffResultDescriptor("diff_roles") modified_roles = DiffResultDescriptor("diff_roles") def diff_roles(self) -> None: """Generate the difference in roles between the policies.""" self.log.info( "Generating role differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_roles, self.removed_roles, matched_roles = self._set_diff( (role_wrapper_factory(r) for r in self.left_policy.roles()), (role_wrapper_factory(r) for r in self.right_policy.roles())) self.modified_roles = dict() for left_role, right_role in matched_roles: # Criteria for modified roles # 1. change to type set, or # 2. change to attribute set (not implemented) added_types, removed_types, matched_types = self._set_diff( (type_wrapper_factory(t) for t in left_role.types()), (type_wrapper_factory(t) for t in right_role.types())) if added_types or removed_types: self.modified_roles[left_role] = ModifiedRole(added_types, removed_types, matched_types) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting role differences") self.added_roles = None self.removed_roles = None self.modified_roles = None setools-4.4.0/setools/diff/terules.py000066400000000000000000000616421402045477700176670ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from collections import defaultdict from sys import intern from enum import Enum from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Optional, Set, Tuple, Union from ..exception import RuleNotConditional, RuleUseError, TERuleNoFilename from ..policyrep import AnyTERule, AVRule, AVRuleXperm, Conditional, IoctlSet, TERuletype, Type from .conditional import conditional_wrapper_factory from .descriptors import DiffResultDescriptor from .difference import Difference, Wrapper from .types import type_wrapper_factory, type_or_attr_wrapper_factory from .typing import RuleList from .objclass import class_wrapper_factory TERULES_UNCONDITIONAL = intern("<>") TERULES_UNCONDITIONAL_BLOCK = intern("True") class ModifiedAVRule(NamedTuple): """Difference details for a modified access vector rule.""" rule: AVRule added_perms: Union[Set[str], IoctlSet] removed_perms: Union[Set[str], IoctlSet] matched_perms: Union[Set[str], IoctlSet] class ModifiedTERule(NamedTuple): """Difference details for a modified type_* rule.""" rule: AVRule added_default: Type removed_default: Type # # Internal datastructure types # class Side(Enum): left = 0 right = 1 class RuleDBSideDataRecord(NamedTuple): perms: Set[str] orig_rule: AVRule class RuleDBSidesRecord(NamedTuple): left: Optional[RuleDBSideDataRecord] right: Optional[RuleDBSideDataRecord] class TypeDBRecord(NamedTuple): left: Dict[str, Type] right: Dict[str, Type] # These conditional items are unioned with str to handle unconditional rules CondExp = Union[Conditional, str] CondBlock = Union[bool, str] RuleDB = Dict[CondExp, Dict[CondBlock, Dict[str, Dict[str, Dict[str, RuleDBSidesRecord]]]]] def _avrule_expand_generator(rule_list: List[AVRule], rule_db: RuleDB, type_db: TypeDBRecord, side: Side) -> None: """ Using rule_list, build up rule_db which is a data structure which consists of nested dicts that store BOTH the left and the right policies. All of the keys are interned strings. The permissions are stored as a set. The basic structure is rule_db[cond_exp][block_bool][src][tgt][tclass] = sides where: cond_exp is a boolean expression block_bool is either true or false src is the source type tgt is the target type tclass is the target class sides is a named tuple with attributes "left" and "right" referring to the left or right policy. Each attribute in the sides named tuple refers to a named tuple with attributes "perms" and "orig_rule" which refer to a permission set and the original unexpanded rule. sides = ((left_perms, left_orig_rule),(right_perms, right_orig_rule)) There are a few advantages to this structure. First, it takes up way less memory. Second, it allows redundant rules to be easily eliminated. And, third, it makes it easy to create the added, removed, and modified rules. """ if side == Side.left: types = type_db.left else: types = type_db.right for unexpanded_rule in rule_list: try: cond_exp = intern(str(unexpanded_rule.conditional)) block_bool = intern(str(unexpanded_rule.conditional_block)) except RuleNotConditional: cond_exp = TERULES_UNCONDITIONAL block_bool = TERULES_UNCONDITIONAL_BLOCK if cond_exp not in rule_db: rule_db[cond_exp] = dict() rule_db[cond_exp][block_bool] = dict() elif block_bool not in rule_db[cond_exp]: rule_db[cond_exp][block_bool] = dict() tclass = unexpanded_rule.tclass.name perms = set(unexpanded_rule.perms) side_data = RuleDBSideDataRecord(perms, unexpanded_rule) block = rule_db[cond_exp][block_bool] for src in unexpanded_rule.source.expand(): src_str = src.name if src_str not in types: types[src_str] = src if src_str not in block: block[src_str] = dict() for tgt in unexpanded_rule.target.expand(): tgt_str = tgt.name if tgt_str not in types: types[tgt_str] = tgt if tgt_str not in block[src_str]: block[src_str][tgt_str] = dict() left_side = None right_side = None if tclass in block[src_str][tgt_str]: sides = block[src_str][tgt_str][tclass] left_side = sides.left right_side = sides.right if side == Side.left: if not left_side: left_side = side_data else: """ The original tuple and perm set might be shared with many expanded rules so a new ones must created. Using "|=" would cause the old perm set to be modified instead of creating a new one. """ p = left_side.perms | perms orig = left_side.orig_rule left_side = RuleDBSideDataRecord(p, orig) else: if not right_side: right_side = side_data else: """ Must create new tuple and perm set as explained above. """ p = right_side.perms | perms orig = right_side.orig_rule right_side = RuleDBSideDataRecord(p, orig) block[src_str][tgt_str][tclass] = RuleDBSidesRecord(left_side, right_side) def _av_remove_redundant_rules(rule_db: RuleDB) -> None: uncond_block = rule_db[TERULES_UNCONDITIONAL][TERULES_UNCONDITIONAL_BLOCK] for cond_exp, cond_blocks in rule_db.items(): if cond_exp == TERULES_UNCONDITIONAL: continue for block in cond_blocks.values(): for src, src_data in block.items(): if src not in uncond_block: continue for tgt, tgt_data in src_data.items(): if tgt not in uncond_block[src]: continue for tclass, side_data in tgt_data.items(): if tclass not in uncond_block[src][tgt]: continue uncond_side_data = uncond_block[src][tgt][tclass] left_side = side_data.left right_side = side_data.right if uncond_side_data.left and left_side: c = left_side.perms & uncond_side_data.left.perms if c: p = left_side.perms - c if p: left_side = RuleDBSideDataRecord(p, left_side.orig_rule) else: left_side = None tgt_data[tclass] = RuleDBSidesRecord(left_side, right_side) if uncond_side_data.right and right_side: c = right_side.perms & uncond_side_data.right.perms if c: p = right_side.perms - c if p: right_side = RuleDBSideDataRecord(p, right_side.orig_rule) else: right_side = None tgt_data[tclass] = RuleDBSidesRecord(left_side, right_side) def _av_generate_diffs(rule_db: RuleDB, type_db: TypeDBRecord) -> \ Tuple[List[AVRule], List[AVRule], List[ModifiedAVRule]]: added: List[AVRule] = [] removed: List[AVRule] = [] modified: List[ModifiedAVRule] = [] for cond_blocks in rule_db.values(): for block in cond_blocks.values(): for src, src_data in block.items(): for tgt, tgt_data in src_data.items(): for side_data in tgt_data.values(): if side_data.left and side_data.right: common_perms = side_data.left.perms & side_data.right.perms left_perms = side_data.left.perms - common_perms right_perms = side_data.right.perms - common_perms if left_perms or right_perms: original_rule = side_data.left.orig_rule rule = original_rule.derive_expanded( type_db.left[src], type_db.left[tgt], side_data.left.perms) modified.append(ModifiedAVRule(rule, right_perms, left_perms, common_perms)) elif side_data.left: original_rule = side_data.left.orig_rule rule = original_rule.derive_expanded( type_db.left[src], type_db.left[tgt], side_data.left.perms) removed.append(rule) elif side_data.right: original_rule = side_data.right.orig_rule rule = original_rule.derive_expanded( type_db.right[src], type_db.right[tgt], side_data.right.perms) added.append(rule) return added, removed, modified def av_diff_template(ruletype: str) -> Callable[["TERulesDifference"], None]: """ This is a template for the access vector diff functions. Parameters: ruletype The rule type, e.g. "allow". """ ruletype = TERuletype.lookup(ruletype) def diff(self) -> None: """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if self._left_te_rules is None or self._right_te_rules is None: self._create_te_rule_lists() type_db = TypeDBRecord(dict(), dict()) rule_db: RuleDB = dict() rule_db[TERULES_UNCONDITIONAL] = dict() rule_db[TERULES_UNCONDITIONAL][TERULES_UNCONDITIONAL_BLOCK] = dict() self.log.info("Expanding AV rules from {0.left_policy}.".format(self)) _avrule_expand_generator(self._left_te_rules[ruletype], rule_db, type_db, Side.left) self.log.info("Expanding AV rules from {0.right_policy}.".format(self)) _avrule_expand_generator(self._right_te_rules[ruletype], rule_db, type_db, Side.right) self.log.info("Removing redundant AV rules.") _av_remove_redundant_rules(rule_db) self.log.info("Generating AV rule diff.") added, removed, modified = _av_generate_diffs(rule_db, type_db) type_db.left.clear() type_db.right.clear() rule_db.clear() setattr(self, "added_{0}s".format(ruletype), added) setattr(self, "removed_{0}s".format(ruletype), removed) setattr(self, "modified_{0}s".format(ruletype), modified) return diff def _avxrule_expand_generator(rule_list: Iterable[AVRuleXperm]) -> Iterable["AVRuleXpermWrapper"]: """ Generator that yields wrapped, expanded, av(x) rules with unioned permission sets. """ items: Dict["AVRuleXpermWrapper", "AVRuleXpermWrapper"] = dict() for unexpanded_rule in rule_list: for expanded_rule in unexpanded_rule.expand(): expanded_wrapped_rule = AVRuleXpermWrapper(expanded_rule) # create a hash table (dict) with the first rule # as the key and value. Rules where permission sets should # be unioned together have the same hash, so this will union # the permissions together. try: items[expanded_wrapped_rule].perms |= expanded_wrapped_rule.perms except KeyError: items[expanded_wrapped_rule] = expanded_wrapped_rule if items: logging.getLogger(__name__).debug( "Expanded {0.ruletype} rules for {0.policy}: {1}".format( unexpanded_rule, len(items))) return items.keys() def avx_diff_template(ruletype: str) -> Callable[["TERulesDifference"], None]: """ This is a template for the extended permission access vector diff functions. Parameters: ruletype The rule type, e.g. "allowxperm". """ ruletype = TERuletype.lookup(ruletype) def diff(self) -> None: """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if not self._left_te_rules or not self._right_te_rules: self._create_te_rule_lists() added, removed, matched = self._set_diff( _avxrule_expand_generator(self._left_te_rules[ruletype]), _avxrule_expand_generator(self._right_te_rules[ruletype]), unwrap=False) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to permissions added_perms, removed_perms, matched_perms = self._set_diff(left_rule.perms, right_rule.perms, unwrap=False) # the final set comprehension is to avoid having lists # like [("perm1", "perm1"), ("perm2", "perm2")], as the # matched_perms return from _set_diff is a set of tuples if added_perms or removed_perms: modified.append(ModifiedAVRule(left_rule.origin, IoctlSet(added_perms), IoctlSet(removed_perms), IoctlSet(p[0] for p in matched_perms))) setattr(self, "added_{0}s".format(ruletype), set(a.origin for a in added)) setattr(self, "removed_{0}s".format(ruletype), set(r.origin for r in removed)) setattr(self, "modified_{0}s".format(ruletype), modified) return diff def te_diff_template(ruletype: str) -> Callable[[Any], None]: """ This is a template for the type_* diff functions. Parameters: ruletype The rule type, e.g. "type_transition". """ ruletype = TERuletype.lookup(ruletype) def diff(self) -> None: """Generate the difference in rules between the policies.""" self.log.info( "Generating {0} differences from {1.left_policy} to {1.right_policy}". format(ruletype, self)) if self._left_te_rules is None or self._right_te_rules is None: self._create_te_rule_lists() added, removed, matched = self._set_diff( self._expand_generator(self._left_te_rules[ruletype], TERuleWrapper), self._expand_generator(self._right_te_rules[ruletype], TERuleWrapper)) modified = [] for left_rule, right_rule in matched: # Criteria for modified rules # 1. change to default type if type_wrapper_factory(left_rule.default) != type_wrapper_factory(right_rule.default): modified.append(ModifiedTERule(left_rule, right_rule.default, left_rule.default)) setattr(self, "added_{0}s".format(ruletype), added) setattr(self, "removed_{0}s".format(ruletype), removed) setattr(self, "modified_{0}s".format(ruletype), modified) return diff class TERulesDifference(Difference): """ Determine the difference in type enforcement rules between two policies. """ diff_allows = av_diff_template("allow") added_allows = DiffResultDescriptor("diff_allows") removed_allows = DiffResultDescriptor("diff_allows") modified_allows = DiffResultDescriptor("diff_allows") diff_auditallows = av_diff_template("auditallow") added_auditallows = DiffResultDescriptor("diff_auditallows") removed_auditallows = DiffResultDescriptor("diff_auditallows") modified_auditallows = DiffResultDescriptor("diff_auditallows") diff_neverallows = av_diff_template("neverallow") added_neverallows = DiffResultDescriptor("diff_neverallows") removed_neverallows = DiffResultDescriptor("diff_neverallows") modified_neverallows = DiffResultDescriptor("diff_neverallows") diff_dontaudits = av_diff_template("dontaudit") added_dontaudits = DiffResultDescriptor("diff_dontaudits") removed_dontaudits = DiffResultDescriptor("diff_dontaudits") modified_dontaudits = DiffResultDescriptor("diff_dontaudits") diff_allowxperms = avx_diff_template("allowxperm") added_allowxperms = DiffResultDescriptor("diff_allowxperms") removed_allowxperms = DiffResultDescriptor("diff_allowxperms") modified_allowxperms = DiffResultDescriptor("diff_allowxperms") diff_auditallowxperms = avx_diff_template("auditallowxperm") added_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") removed_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") modified_auditallowxperms = DiffResultDescriptor("diff_auditallowxperms") diff_neverallowxperms = avx_diff_template("neverallowxperm") added_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") removed_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") modified_neverallowxperms = DiffResultDescriptor("diff_neverallowxperms") diff_dontauditxperms = avx_diff_template("dontauditxperm") added_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") removed_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") modified_dontauditxperms = DiffResultDescriptor("diff_dontauditxperms") diff_type_transitions = te_diff_template("type_transition") added_type_transitions = DiffResultDescriptor("diff_type_transitions") removed_type_transitions = DiffResultDescriptor("diff_type_transitions") modified_type_transitions = DiffResultDescriptor("diff_type_transitions") diff_type_changes = te_diff_template("type_change") added_type_changes = DiffResultDescriptor("diff_type_changes") removed_type_changes = DiffResultDescriptor("diff_type_changes") modified_type_changes = DiffResultDescriptor("diff_type_changes") diff_type_members = te_diff_template("type_member") added_type_members = DiffResultDescriptor("diff_type_members") removed_type_members = DiffResultDescriptor("diff_type_members") modified_type_members = DiffResultDescriptor("diff_type_members") _left_te_rules: RuleList[TERuletype, AnyTERule] = None _right_te_rules: RuleList[TERuletype, AnyTERule] = None # # Internal functions # def _create_te_rule_lists(self) -> None: """Create rule lists for both policies.""" # do not expand yet, to keep memory # use down as long as possible self.log.debug("Building TE rule lists from {0.left_policy}".format(self)) self._left_te_rules = defaultdict(list) for rule in self.left_policy.terules(): self._left_te_rules[rule.ruletype].append(rule) for ruletype, rules in self._left_te_rules.items(): self.log.debug("Loaded {0} {1} rules.".format(len(rules), ruletype)) self.log.debug("Building TE rule lists from {0.right_policy}".format(self)) self._right_te_rules = defaultdict(list) for rule in self.right_policy.terules(): self._right_te_rules[rule.ruletype].append(rule) for ruletype, rules in self._right_te_rules.items(): self.log.debug("Loaded {0} {1} rules.".format(len(rules), ruletype)) self.log.debug("Completed building TE rule lists.") def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting TE rule differences") self.added_allows = None self.removed_allows = None self.modified_allows = None self.added_auditallows = None self.removed_auditallows = None self.modified_auditallows = None self.added_neverallows = None self.removed_neverallows = None self.modified_neverallows = None self.added_dontaudits = None self.removed_dontaudits = None self.modified_dontaudits = None self.added_allowxperms = None self.removed_allowxperms = None self.modified_allowxperms = None self.added_auditallowxperms = None self.removed_auditallowxperms = None self.modified_auditallowxperms = None self.added_neverallowxperms = None self.removed_neverallowxperms = None self.modified_neverallowxperms = None self.added_dontauditxperms = None self.removed_dontauditxperms = None self.modified_dontauditxperms = None self.added_type_transitions = None self.removed_type_transitions = None self.modified_type_transitions = None self.added_type_changes = None self.removed_type_changes = None self.modified_type_changes = None self.added_type_members = None self.removed_type_members = None self.modified_type_members = None # Lists of rules for each policy self._left_te_rules = None self._right_te_rules = None # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class AVRuleXpermWrapper(Wrapper[AVRuleXperm]): # pylint: disable=unsubscriptable-object """Wrap extended permission access vector rules to allow set operations.""" __slots__ = ("source", "target", "tclass", "xperm_type", "perms") def __init__(self, rule: AVRuleXperm) -> None: self.origin = rule self.source = type_or_attr_wrapper_factory(rule.source) self.target = type_or_attr_wrapper_factory(rule.target) self.tclass = class_wrapper_factory(rule.tclass) self.xperm_type = rule.xperm_type self.perms = set(rule.perms) self.key = hash(rule) def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because TERuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass and \ self.xperm_type == other.xperm_type # Pylint bug: https://github.com/PyCQA/pylint/issues/2822 class TERuleWrapper(Wrapper): # pylint: disable=unsubscriptable-object """Wrap type_* rules to allow set operations.""" __slots__ = ("source", "target", "tclass", "conditional", "conditional_block", "filename") def __init__(self, rule): self.origin = rule self.source = type_or_attr_wrapper_factory(rule.source) self.target = type_or_attr_wrapper_factory(rule.target) self.tclass = class_wrapper_factory(rule.tclass) self.key = hash(rule) try: self.conditional = conditional_wrapper_factory(rule.conditional) self.conditional_block = rule.conditional_block except RuleNotConditional: self.conditional = None self.conditional_block = None try: self.filename = rule.filename except (RuleUseError, TERuleNoFilename): self.filename = None def __hash__(self): return self.key def __lt__(self, other): return self.key < other.key def __eq__(self, other): # because TERuleDifference groups rules by ruletype, # the ruletype always matches. return self.source == other.source and \ self.target == other.target and \ self.tclass == other.tclass and \ self.conditional == other.conditional and \ self.conditional_block == other.conditional_block and \ self.filename == other.filename setools-4.4.0/setools/diff/typeattr.py000066400000000000000000000066541402045477700200620ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple, Set from ..policyrep import Type, TypeAttribute from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .typing import SymbolCache _typeattr_cache: SymbolCache[TypeAttribute] = defaultdict(dict) class ModifiedTypeAttribute(NamedTuple): """Difference details for a modified type attribute.""" added_types: Set[Type] removed_types: Set[Type] matched_types: Set[Type] def typeattr_wrapper_factory(attr: TypeAttribute) -> SymbolWrapper[TypeAttribute]: """ Wrap type attributes from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _typeattr_cache[attr.policy][attr] except KeyError: a = SymbolWrapper(attr) _typeattr_cache[attr.policy][attr] = a return a class TypeAttributesDifference(Difference): """Determine the difference in type attributes between two policies.""" added_type_attributes = DiffResultDescriptor("diff_type_attributes") removed_type_attributes = DiffResultDescriptor("diff_type_attributes") modified_type_attributes = DiffResultDescriptor("diff_type_attributes") def diff_type_attributes(self) -> None: """Generate the difference in type attributes between the policies.""" self.log.info( "Generating type attribute differences from {0.left_policy} to {0.right_policy}". format(self)) self.added_type_attributes, self.removed_type_attributes, matched_attributes = \ self._set_diff( (SymbolWrapper(r) for r in self.left_policy.typeattributes()), (SymbolWrapper(r) for r in self.right_policy.typeattributes())) self.modified_type_attributes = dict() for left_attribute, right_attribute in matched_attributes: # Criteria for modified attributes # 1. change to type set added_types, removed_types, matched_types = self._set_diff( (SymbolWrapper(t) for t in left_attribute.expand()), (SymbolWrapper(t) for t in right_attribute.expand())) if added_types or removed_types: self.modified_type_attributes[left_attribute] = ModifiedTypeAttribute( added_types, removed_types, matched_types) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting type attribute differences") self.added_type_attributes = None self.removed_type_attributes = None self.modified_type_attributes = None setools-4.4.0/setools/diff/types.py000066400000000000000000000114541402045477700173440ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple, Set, Union from ..policyrep import Type, TypeAttribute, TypeOrAttr from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .typeattr import typeattr_wrapper_factory from .typing import SymbolCache _types_cache: SymbolCache[Type] = defaultdict(dict) class ModifiedType(NamedTuple): """Difference details for a modified type.""" added_attributes: Set[TypeAttribute] removed_attributes: Set[TypeAttribute] matched_attributes: Set[TypeAttribute] modified_permissive: bool permissive: bool added_aliases: Set[str] removed_aliases: Set[str] matched_aliases: Set[str] def type_wrapper_factory(type_: Type) -> SymbolWrapper[Type]: """ Wrap types from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _types_cache[type_.policy][type_] except KeyError: t = SymbolWrapper(type_) _types_cache[type_.policy][type_] = t return t def type_or_attr_wrapper_factory(type_: TypeOrAttr) -> \ Union[SymbolWrapper[Type], SymbolWrapper[TypeAttribute]]: """ Wrap types or attributes from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ if isinstance(type_, Type): return type_wrapper_factory(type_) else: return typeattr_wrapper_factory(type_) class TypesDifference(Difference): """Determine the difference in types between two policies.""" added_types = DiffResultDescriptor("diff_types") removed_types = DiffResultDescriptor("diff_types") modified_types = DiffResultDescriptor("diff_types") def diff_types(self) -> None: """Generate the difference in types between the policies.""" self.log.info( "Generating type differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_types, self.removed_types, matched_types = self._set_diff( (SymbolWrapper(t) for t in self.left_policy.types()), (SymbolWrapper(t) for t in self.right_policy.types())) self.modified_types = dict() for left_type, right_type in matched_types: # Criteria for modified types # 1. change to attribute set, or # 2. change to alias set, or # 3. different permissive setting added_attr, removed_attr, matched_attr = self._set_diff( (SymbolWrapper(a) for a in left_type.attributes()), (SymbolWrapper(a) for a in right_type.attributes())) added_aliases, removed_aliases, matched_aliases = self._set_diff(left_type.aliases(), right_type.aliases(), unwrap=False) left_permissive = left_type.ispermissive right_permissive = right_type.ispermissive mod_permissive = left_permissive != right_permissive if added_attr or removed_attr or added_aliases or removed_aliases or mod_permissive: self.modified_types[left_type] = ModifiedType(added_attr, removed_attr, matched_attr, mod_permissive, left_permissive, added_aliases, removed_aliases, matched_aliases) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting type differences") self.added_types = None self.removed_types = None self.modified_types = None setools-4.4.0/setools/diff/typing.py000066400000000000000000000020301402045477700175000ustar00rootroot00000000000000# This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import DefaultDict, Dict, List, Optional, TypeVar from ..policyrep import PolicyObject, SELinuxPolicy from .difference import Wrapper, SymbolWrapper T = TypeVar("T", bound=PolicyObject) U = TypeVar("U", bound=Wrapper) Cache = DefaultDict[SELinuxPolicy, Dict[T, U]] SymbolCache = Cache[T, SymbolWrapper[T]] RuleList = Optional[DefaultDict[T, List[U]]] setools-4.4.0/setools/diff/users.py000066400000000000000000000137461402045477700173470ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from typing import NamedTuple, Set, Optional, Union from ..exception import MLSDisabled from ..policyrep import Level, Range, Role, User from .descriptors import DiffResultDescriptor from .difference import Difference, SymbolWrapper from .mls import LevelWrapper, RangeWrapper from .roles import role_wrapper_factory from .typing import SymbolCache _users_cache: SymbolCache[User] = defaultdict(dict) class ModifiedUser(NamedTuple): """Difference details for a modified user.""" added_roles: Set[Role] removed_roles: Set[Role] matched_roles: Set[Role] added_level: Optional[Union[Level, str]] removed_level: Optional[Union[Level, str]] added_range: Optional[Union[Range, str]] removed_range: Optional[Union[Range, str]] def user_wrapper_factory(user: User) -> SymbolWrapper[User]: """ Wrap users from the specified policy. This caches results to prevent duplicate wrapper objects in memory. """ try: return _users_cache[user.policy][user] except KeyError: r = SymbolWrapper(user) _users_cache[user.policy][user] = r return r class UsersDifference(Difference): """Determine the difference in users between two policies.""" added_users = DiffResultDescriptor("diff_users") removed_users = DiffResultDescriptor("diff_users") modified_users = DiffResultDescriptor("diff_users") def diff_users(self) -> None: """Generate the difference in users between the policies.""" self.log.info( "Generating user differences from {0.left_policy} to {0.right_policy}".format(self)) self.added_users, self.removed_users, matched_users = self._set_diff( (user_wrapper_factory(r) for r in self.left_policy.users()), (user_wrapper_factory(r) for r in self.right_policy.users())) self.modified_users = dict() for left_user, right_user in matched_users: # Criteria for modified users # 1. change to role set, or # 2. change to default level, or # 3. change to range added_roles, removed_roles, matched_roles = self._set_diff( (role_wrapper_factory(r) for r in left_user.roles), (role_wrapper_factory(r) for r in right_user.roles)) # keep wrapped and unwrapped MLS objects here so there # are not several nested try blocks left_level_wrap: Optional[LevelWrapper] left_range_wrap: Optional[RangeWrapper] left_level: Union[Level, str] left_range: Union[Range, str] right_level_wrap: Optional[LevelWrapper] right_range_wrap: Optional[RangeWrapper] right_level: Union[Level, str] right_range: Union[Range, str] added_level: Optional[Union[Level, str]] added_range: Optional[Union[Range, str]] removed_level: Optional[Union[Level, str]] removed_range: Optional[Union[Range, str]] try: left_level_wrap = LevelWrapper(left_user.mls_level) left_range_wrap = RangeWrapper(left_user.mls_range) left_level = left_user.mls_level left_range = left_user.mls_range except MLSDisabled: left_level_wrap = None left_range_wrap = None left_level = "None (MLS Disabled)" left_range = "None (MLS Disabled)" try: right_level_wrap = LevelWrapper(right_user.mls_level) right_range_wrap = RangeWrapper(right_user.mls_range) right_level = right_user.mls_level right_range = right_user.mls_range except MLSDisabled: right_level_wrap = None right_range_wrap = None right_level = "None (MLS Disabled)" right_range = "None (MLS Disabled)" if left_level_wrap != right_level_wrap: added_level = right_level removed_level = left_level else: added_level = None removed_level = None if left_range_wrap != right_range_wrap: added_range = right_range removed_range = left_range else: added_range = None removed_range = None if added_roles or removed_roles or removed_level or removed_range: self.modified_users[left_user] = ModifiedUser(added_roles, removed_roles, matched_roles, added_level, removed_level, added_range, removed_range) # # Internal functions # def _reset_diff(self) -> None: """Reset diff results on policy changes.""" self.log.debug("Resetting user differences") self.added_users = None self.removed_users = None self.modified_users = None setools-4.4.0/setools/dta.py000066400000000000000000000555011402045477700160410ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=unsubscriptable-object import itertools import logging from collections import defaultdict from contextlib import suppress from typing import DefaultDict, Iterable, List, NamedTuple, Optional, Union import networkx as nx from networkx.exception import NetworkXError, NetworkXNoPath, NodeNotFound from .descriptors import EdgeAttrDict, EdgeAttrList from .policyrep import AnyTERule, SELinuxPolicy, TERuletype, Type __all__ = ['DomainTransitionAnalysis', 'DomainTransition', 'DomainEntrypoint', 'DTAPath'] class DomainEntrypoint(NamedTuple): """Entrypoint list entry named tuple output format.""" name: Type entrypoint: List[AnyTERule] execute: List[AnyTERule] type_transition: List[AnyTERule] class DomainTransition(NamedTuple): """Transition step output named tuple format.""" source: Type target: Type transition: List[AnyTERule] entrypoints: List[DomainEntrypoint] setexec: List[AnyTERule] dyntransition: List[AnyTERule] setcurrent: List[AnyTERule] # # Typing # DTAPath = Iterable[DomainTransition] RuleHash = DefaultDict[Type, List[AnyTERule]] class DomainTransitionAnalysis: """Domain transition analysis.""" _exclude: List[Type] _reverse: bool def __init__(self, policy: SELinuxPolicy, reverse: bool = False, exclude: Optional[Iterable[Union[Type, str]]] = None) -> None: """ Parameter: policy The policy to analyze. Keyword Parameters: reverse True means reverse the direction of the analysis (find parent domains). exclude An iterable of types to exclude from the analysis. """ self.log = logging.getLogger(__name__) self.policy = policy self.exclude = exclude # type: ignore # https://github.com/python/mypy/issues/220 self.reverse = reverse self.rebuildgraph = True self.rebuildsubgraph = True self.G = nx.DiGraph() self.subG = self.G.copy() @property def reverse(self) -> bool: return self._reverse @reverse.setter def reverse(self, direction) -> None: self._reverse = bool(direction) self.rebuildsubgraph = True @property def exclude(self) -> List[Type]: return self._exclude @exclude.setter def exclude(self, types: Optional[Iterable[Union[Type, str]]]) -> None: if types: self._exclude = [self.policy.lookup_type(t) for t in types] else: self._exclude = [] self.rebuildsubgraph = True def shortest_path(self, source: Union[Type, str], target: Union[Type, str]) \ -> Iterable[DTAPath]: """ Generator which yields one shortest domain transition path between the source and target types (there may be more). Parameters: source The source type. target The target type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s: Type = self.policy.lookup_type(source) t: Type = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating one domain transition path from {0} to {1}...".format(s, t)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph # pylint: disable=unexpected-keyword-arg, no-value-for-parameter yield self.__generate_steps(nx.shortest_path(self.subG, source=s, target=t)) def all_paths(self, source: Union[Type, str], target: Union[Type, str], maxlen: int = 2) \ -> Iterable[DTAPath]: """ Generator which yields all domain transition paths between the source and target up to the specified maximum path length. Parameters: source The source type. target The target type. maxlen Maximum length of paths. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ if maxlen < 1: raise ValueError("Maximum path length must be positive.") s: Type = self.policy.lookup_type(source) t: Type = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all domain transition paths from {0} to {1}, max length {2}...". format(s, t, maxlen)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph for path in nx.all_simple_paths(self.subG, s, t, maxlen): yield self.__generate_steps(path) def all_shortest_paths(self, source: Union[Type, str], target: Union[Type, str]) \ -> Iterable[DTAPath]: """ Generator which yields all shortest domain transition paths between the source and target types. Parameters: source The source type. target The target type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s: Type = self.policy.lookup_type(source) t: Type = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all shortest domain transition paths from {0} to {1}...". format(s, t)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. excluded # NetworkXNoPath: no paths or the target type is # not in the graph for path in nx.all_shortest_paths(self.subG, s, t): yield self.__generate_steps(path) def transitions(self, type_: Union[Type, str]) -> DTAPath: """ Generator which yields all domain transitions out of a specified source type. Parameters: type_ The starting type. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each domain transition. """ s: Type = self.policy.lookup_type(type_) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all domain transitions {1} {0}". format(s, "in to" if self.reverse else "out from")) with suppress(NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. excluded for source, target in self.subG.out_edges(s): edge = Edge(self.subG, source, target) if self.reverse: real_source, real_target = target, source else: real_source, real_target = source, target yield DomainTransition(real_source, real_target, edge.transition, self.__generate_entrypoints(edge), edge.setexec, edge.dyntransition, edge.setcurrent) def get_stats(self) -> str: # pragma: no cover """ Get the domain transition graph statistics. Return: str """ if self.rebuildgraph: self._build_graph() return nx.info(self.G) # # Internal functions follow # @staticmethod def __generate_entrypoints(edge: 'Edge') -> List[DomainEntrypoint]: """ Creates a list of entrypoint, execute, and type_transition rules for each entrypoint. Parameter: data The dictionary of entrypoints. Return: list of tuple(type, entry, exec, trans) type The entrypoint type. entry The list of entrypoint rules. exec The list of execute rules. trans The list of type_transition rules. """ return [DomainEntrypoint(e, edge.entrypoint[e], edge.execute[e], edge.type_transition[e]) for e in edge.entrypoint] def __generate_steps(self, path: List[Type]) -> DTAPath: """ Generator which yields the source, target, and associated rules for each domain transition. Parameter: path A list of graph node names representing an information flow path. Yield: tuple(source, target, transition, entrypoints, setexec, dyntransition, setcurrent) source The source type for this step of the domain transition. target The target type for this step of the domain transition. transition The list of transition rules. entrypoints Generator which yields entrypoint-related rules. setexec The list of setexec rules. dyntranstion The list of dynamic transition rules. setcurrent The list of setcurrent rules. """ for s in range(1, len(path)): source: Type = path[s - 1] target: Type = path[s] edge = Edge(self.subG, source, target) # Yield the actual source and target. # The above perspective is reversed # if the graph has been reversed. if self.reverse: real_source, real_target = target, source else: real_source, real_target = source, target yield DomainTransition(real_source, real_target, edge.transition, self.__generate_entrypoints(edge), edge.setexec, edge.dyntransition, edge.setcurrent) # # Graph building functions # # Domain transition requirements: # # Standard transitions a->b: # allow a b:process transition; # allow a b_exec:file execute; # allow b b_exec:file entrypoint; # # and at least one of: # allow a self:process setexec; # type_transition a b_exec:process b; # # Dynamic transition x->y: # allow x y:process dyntransition; # allow x self:process setcurrent; # # Algorithm summary: # 1. iterate over all rules # 1. skip non allow/type_transition rules # 2. if process transition or dyntransition, create edge, # initialize rule lists, add the (dyn)transition rule # 3. if process setexec or setcurrent, add to appropriate dict # keyed on the subject # 4. if file exec, entrypoint, or type_transition:process, # add to appropriate dict keyed on subject,object. # 2. Iterate over all graph edges: # 1. if there is a transition rule (else add to invalid # transition list): # 1. use set intersection to find matching exec # and entrypoint rules. If none, add to invalid # transition list. # 2. for each valid entrypoint, add rules to the # edge's lists if there is either a # type_transition for it or the source process # has setexec permissions. # 3. If there are neither type_transitions nor # setexec permissions, add to the invalid # transition list # 2. if there is a dyntransition rule (else add to invalid # dyntrans list): # 1. If the source has a setcurrent rule, add it # to the edge's list, else add to invalid # dyntransition list. # 3. Iterate over all graph edges: # 1. if the edge has an invalid trans and dyntrans, delete # the edge. # 2. if the edge has an invalid trans, clear the related # lists on the edge. # 3. if the edge has an invalid dyntrans, clear the related # lists on the edge. # def _build_graph(self) -> None: self.G.clear() self.G.name = "Domain transition graph for {0}.".format(self.policy) self.log.info("Building domain transition graph from {0}...".format(self.policy)) # hash tables keyed on domain type setexec: RuleHash = defaultdict(list) setcurrent: RuleHash = defaultdict(list) # hash tables keyed on (domain, entrypoint file type) # the parameter for defaultdict has to be callable # hence the lambda for the nested defaultdict execute: DefaultDict[Type, RuleHash] = defaultdict(lambda: defaultdict(list)) entrypoint: DefaultDict[Type, RuleHash] = defaultdict(lambda: defaultdict(list)) # hash table keyed on (domain, entrypoint, target domain) type_trans: DefaultDict[Type, DefaultDict[Type, RuleHash]] = \ defaultdict(lambda: defaultdict(lambda: defaultdict(list))) for rule in self.policy.terules(): if rule.ruletype == TERuletype.allow: if rule.tclass not in ["process", "file"]: continue if rule.tclass == "process": if "transition" in rule.perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add edges if they actually # transition to a new type if s != t: edge = Edge(self.G, s, t, create=True) edge.transition.append(rule) if "dyntransition" in rule.perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add edges if they actually # transition to a new type if s != t: e = Edge(self.G, s, t, create=True) e.dyntransition.append(rule) if "setexec" in rule.perms: for s in rule.source.expand(): setexec[s].append(rule) if "setcurrent" in rule.perms: for s in rule.source.expand(): setcurrent[s].append(rule) else: if "execute" in rule.perms: for s, t in itertools.product( rule.source.expand(), rule.target.expand()): execute[s][t].append(rule) if "entrypoint" in rule.perms: for s, t in itertools.product(rule.source.expand(), rule.target.expand()): entrypoint[s][t].append(rule) elif rule.ruletype == TERuletype.type_transition: if rule.tclass != "process": continue d = rule.default for s, t in itertools.product(rule.source.expand(), rule.target.expand()): type_trans[s][t][d].append(rule) invalid_edge: List[Edge] = [] clear_transition: List[Edge] = [] clear_dyntransition: List[Edge] = [] for s, t in self.G.edges(): edge = Edge(self.G, s, t) invalid_trans = False invalid_dyntrans = False if edge.transition: # get matching domain exec w/entrypoint type entry = set(entrypoint[t].keys()) exe = set(execute[s].keys()) match = entry.intersection(exe) if not match: # there are no valid entrypoints invalid_trans = True else: # TODO try to improve the # efficiency in this loop for m in match: # pylint: disable=unsupported-assignment-operation if s in setexec or type_trans[s][m]: # add key for each entrypoint edge.entrypoint[m] += entrypoint[t][m] edge.execute[m] += execute[s][m] if type_trans[s][m][t]: edge.type_transition[m] += type_trans[s][m][t] if s in setexec: edge.setexec.extend(setexec[s]) if not edge.setexec and not edge.type_transition: invalid_trans = True else: invalid_trans = True if edge.dyntransition: if s in setcurrent: edge.setcurrent.extend(setcurrent[s]) else: invalid_dyntrans = True else: invalid_dyntrans = True # cannot change the edges while iterating over them, # so keep appropriate lists if invalid_trans and invalid_dyntrans: invalid_edge.append(edge) elif invalid_trans: clear_transition.append(edge) elif invalid_dyntrans: clear_dyntransition.append(edge) # Remove invalid transitions self.G.remove_edges_from(invalid_edge) for edge in clear_transition: # if only the regular transition is invalid, # clear the relevant lists del edge.transition del edge.execute del edge.entrypoint del edge.type_transition del edge.setexec for edge in clear_dyntransition: # if only the dynamic transition is invalid, # clear the relevant lists del edge.dyntransition del edge.setcurrent self.rebuildgraph = False self.rebuildsubgraph = True self.log.info("Completed building domain transition graph.") self.log.debug("Graph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.G), nx.number_of_edges(self.G))) def __remove_excluded_entrypoints(self) -> None: invalid_edges: List[Edge] = [] for source, target in self.subG.edges(): edge = Edge(self.subG, source, target) entrypoints = set(edge.entrypoint) entrypoints.intersection_update(self.exclude) if not entrypoints: # short circuit if there are no # excluded entrypoint types on # this edge. continue for e in entrypoints: # clear the entrypoint data # pylint: disable=unsupported-delete-operation del edge.entrypoint[e] del edge.execute[e] with suppress(KeyError): # setexec del edge.type_transition[e] # cannot delete the edges while iterating over them if not edge.entrypoint and not edge.dyntransition: invalid_edges.append(edge) self.subG.remove_edges_from(invalid_edges) def _build_subgraph(self) -> None: if self.rebuildgraph: self._build_graph() self.log.info("Building domain transition subgraph.") self.log.debug("Excluding {0}".format(self.exclude)) self.log.debug("Reverse {0}".format(self.reverse)) # reverse graph for reverse DTA if self.reverse: self.subG = self.G.reverse(copy=True) else: self.subG = self.G.copy() if self.exclude: # delete excluded domains from subgraph self.subG.remove_nodes_from(self.exclude) # delete excluded entrypoints from subgraph self.__remove_excluded_entrypoints() self.rebuildsubgraph = False self.log.info("Completed building domain transition subgraph.") self.log.debug("Subgraph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.subG), nx.number_of_edges(self.subG))) class Edge: """ A graph edge. Also used for returning domain transition steps. Parameters: graph The NetworkX graph. source The source type of the edge. target The target tyep of the edge. Keyword Parameters: create (T/F) create the edge if it does not exist. The default is False. """ transition = EdgeAttrList('transition') setexec = EdgeAttrList('setexec') dyntransition = EdgeAttrList('dyntransition') setcurrent = EdgeAttrList('setcurrent') entrypoint = EdgeAttrDict('entrypoint') execute = EdgeAttrDict('execute') type_transition = EdgeAttrDict('type_transition') def __init__(self, graph, source: Type, target: Type, create: bool = False) -> None: self.G = graph self.source: Type = source self.target: Type = target if not self.G.has_edge(source, target): if not create: raise ValueError("Edge does not exist in graph") else: self.G.add_edge(source, target) self.transition = None self.entrypoint = None self.execute = None self.type_transition = None self.setexec = None self.dyntransition = None self.setcurrent = None def __getitem__(self, key): # This is implemented so this object can be used in NetworkX # functions that operate on (source, target) tuples if isinstance(key, slice): return [self._index_to_item(i) for i in range(* key.indices(2))] else: return self._index_to_item(key) def _index_to_item(self, index: int) -> Type: """Return source or target based on index.""" if index == 0: return self.source elif index == 1: return self.target else: raise IndexError("Invalid index (edges only have 2 items): {0}".format(index)) setools-4.4.0/setools/exception.py000066400000000000000000000151251402045477700172650ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Base class for exceptions # class SEToolsException(Exception): """Base class for all SETools exceptions.""" pass # # Policyrep base exception # class PolicyrepException(SEToolsException): """Base class for all policyrep exceptions.""" pass # # General Policyrep exceptions # class LowLevelPolicyError(ValueError, PolicyrepException): """ Exception for low-level policy errors. This is typically due to errors accessing policy data structures. The policy may be malformed or there may be an SETools bug.""" pass class InvalidPolicy(ValueError, PolicyrepException): """Exception for invalid policy.""" pass class MLSDisabled(PolicyrepException): """ Exception when MLS is disabled. """ pass # # Invalid component exceptions # class InvalidSymbol(ValueError, PolicyrepException): """ Base class for invalid symbols. Typically this is attempting to look up an object in the policy, but it does not exist. """ pass class InvalidBoolean(InvalidSymbol): """Exception for invalid Booleans.""" pass class InvalidCategory(InvalidSymbol): """Exception for invalid MLS categories.""" pass class InvalidClass(InvalidSymbol): """Exception for invalid object classes.""" pass class InvalidCommon(InvalidSymbol): """Exception for invalid common permission sets.""" pass class InvalidInitialSid(InvalidSymbol): """Exception for invalid initial sids.""" pass class InvalidLevel(InvalidSymbol): """ Exception for an invalid level. """ pass class InvalidLevelDecl(InvalidSymbol): """ Exception for an invalid level declaration. """ pass class InvalidPermission(InvalidSymbol): """ Exception for an invalid permission. """ pass class InvalidRange(InvalidSymbol): """ Exception for an invalid range. """ pass class InvalidRole(InvalidSymbol): """Exception for invalid roles.""" pass class InvalidSensitivity(InvalidSymbol): """ Exception for an invalid sensitivity. """ pass class InvalidType(InvalidSymbol): """Exception for invalid types and attributes.""" pass class InvalidUser(InvalidSymbol): """Exception for invalid users.""" pass # # Rule type exceptions # class InvalidRuleType(InvalidSymbol): """Exception for invalid rule types.""" pass class InvalidBoundsType(InvalidSymbol): """Exception for invalid *bounds rule types.""" pass class InvalidConstraintType(InvalidSymbol): """Exception for invalid constraint types.""" pass class InvalidDefaultType(InvalidRuleType): """Exception for invalid default_* types.""" pass class InvalidFSUseType(InvalidRuleType): """Exception for invalid fs_use_* types.""" pass class InvalidMLSRuleType(InvalidRuleType): """Exception for invalid MLS rule types.""" pass class InvalidRBACRuleType(InvalidRuleType): """Exception for invalid RBAC rule types.""" pass class InvalidTERuleType(InvalidRuleType): """Exception for invalid TE rule types.""" pass # # Object use errors # class SymbolUseError(AttributeError, PolicyrepException): """ Base class for incorrectly using an object. Typically this is for classes with strong similarities, but with slight variances in functionality, e.g. allow vs type_transition rules. """ pass class RuleUseError(SymbolUseError): """ Base class for incorrect parameters for a rule. For example, trying to get the permissions of a rule that has no permissions. """ pass class ConstraintUseError(SymbolUseError): """Exception when getting permissions from a validatetrans.""" pass class NoStatement(SymbolUseError): """ Exception for objects that have no inherent statement, such as conditional expressions and MLS ranges. """ pass # # Default rule exceptions # class InvalidDefaultValue(InvalidSymbol): """Exception for invalid default (not source/target)""" pass class InvalidDefaultRange(InvalidSymbol): """Exception for invalid default range""" pass # # Other exceptions # class NoCommon(AttributeError, PolicyrepException): """ Exception when a class does not inherit a common permission set. """ pass class NoDefaults(InvalidSymbol): """Exception for classes that have no default_* statements.""" pass class RuleNotConditional(AttributeError, PolicyrepException): """ Exception when getting the conditional expression for rules that are unconditional (not conditional). """ pass class TERuleNoFilename(AttributeError, PolicyrepException): """ Exception when getting the file name of a type_transition rule that has no file name. """ pass # # PolicyChecker exceptions # class InvalidCheckerConfig(SEToolsException): """Base class for invalid checker configurations.""" pass class InvalidCheckerModule(InvalidCheckerConfig): """Exception when an unknown checker module is requested.""" pass class InvalidCheckOption(InvalidCheckerConfig): """Exception for invalid options in a checker module.""" pass class InvalidCheckValue(InvalidCheckerConfig): """Exception for invalid values for a checker module's option.""" pass # # Permission map exceptions # class PermissionMapException(SEToolsException): """Base class for all permission map exceptions.""" pass class PermissionMapParseError(PermissionMapException): """Exception for parse errors while reading permission map files.""" pass class RuleTypeError(PermissionMapException): """Exception for using rules with incorrect rule type.""" pass class UnmappedClass(PermissionMapException): """Exception for classes that are unmapped""" pass class UnmappedPermission(PermissionMapException): """Exception for permissions that are unmapped""" pass setools-4.4.0/setools/fsusequery.py000066400000000000000000000066611402045477700175070ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchContext from .policyrep import FSUse, FSUseRuletype from .query import PolicyQuery from .util import match_regex class FSUseQuery(MatchContext, PolicyQuery): """ Query fs_use_* statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The rule type(s) to match. fs The criteria to match the file system type. fs_regex If true, regular expression matching will be used on the file system type. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ ruletype = CriteriaSetDescriptor(enum_class=FSUseRuletype) fs = CriteriaDescriptor("fs_regex") fs_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(FSUseQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[FSUse]: """Generator which yields all matching fs_use_* statements.""" self.log.info("Generating fs_use_* results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) self._match_context_debug(self.log) for fsu in self.policy.fs_uses(): if self.ruletype and fsu.ruletype not in self.ruletype: continue if self.fs and not match_regex( fsu.fs, self.fs, self.fs_regex): continue if not self._match_context(fsu.context): continue yield fsu setools-4.4.0/setools/genfsconquery.py000066400000000000000000000074711402045477700201640ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable, Optional from .descriptors import CriteriaDescriptor from .mixins import MatchContext from .policyrep import Genfscon from .query import PolicyQuery from .util import match_regex class GenfsconQuery(MatchContext, PolicyQuery): """ Query genfscon statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: fs The criteria to match the file system type. fs_regex If true, regular expression matching will be used on the file system type. path The criteria to match the path. path_regex If true, regular expression matching will be used on the path. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ filetype: Optional[int] = None fs = CriteriaDescriptor("fs_regex") fs_regex: bool = False path = CriteriaDescriptor("path_regex") path_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(GenfsconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Genfscon]: """Generator which yields all matching genfscons.""" self.log.info("Generating genfscon results from {0.policy}".format(self)) self.log.debug("FS: {0.fs!r}, regex: {0.fs_regex}".format(self)) self.log.debug("Path: {0.path!r}, regex: {0.path_regex}".format(self)) self.log.debug("Filetype: {0.filetype!r}".format(self)) self._match_context_debug(self.log) for genfs in self.policy.genfscons(): if self.fs and not match_regex( genfs.fs, self.fs, self.fs_regex): continue if self.path and not match_regex( genfs.path, self.path, self.path_regex): continue if self.filetype and not self.filetype == genfs.filetype: continue if not self._match_context(genfs.context): continue yield genfs setools-4.4.0/setools/ibendportconquery.py000066400000000000000000000072631402045477700210470ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional from .mixins import MatchContext, MatchName from .policyrep import Ibendportcon from .query import PolicyQuery from .util import match_regex class IbendportconQuery(MatchContext, MatchName, PolicyQuery): """ Infiniband endport context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the network interface to match. name_regex If true, regular expression matching will be used for matching the name. port The port number to match. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _port: Optional[int] = None @property def port(self) -> Optional[int]: return self._port @port.setter def port(self, value: Optional[int]) -> None: if value: pending_value = int(value) if not 0 < pending_value < 256: raise ValueError("Endport value must be 1-255.") self._port = pending_value else: self._port = None def __init__(self, policy, **kwargs): super(IbendportconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Ibendportcon]: """Generator which yields all matching ibendportcons.""" self.log.info("Generating ibendportcon results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Port: {0.port!r}".format(self)) self._match_context_debug(self.log) for endport in self.policy.ibendportcons(): if self.name and not match_regex( endport.name, self.name, self.name_regex): continue if self.port is not None and self.port != endport.port: continue if not self._match_context(endport.context): continue yield endport setools-4.4.0/setools/ibpkeyconquery.py000066400000000000000000000130131402045477700203320ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from ipaddress import IPv6Address import logging from typing import Iterable, Optional, Tuple, Union from .mixins import MatchContext from .policyrep import Ibpkeycon, IbpkeyconRange from .query import PolicyQuery from .util import match_range class IbpkeyconQuery(MatchContext, PolicyQuery): """ Infiniband pkey context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: subnet_prefix A subnet prefix to match. pkeys A 2-tuple of the pkey range to match. (Set both to the same value for a single pkey) pkeys_subset If true, the criteria will match if it is a subset of the ibpkeycon's range. pkeys_overlap If true, the criteria will match if it overlaps any of the ibpkeycon's range. pkeys_superset If true, the criteria will match if it is a superset of the ibpkeycon's range. pkeys_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _subnet_prefix: Optional[IPv6Address] = None _pkeys: Optional[IbpkeyconRange] = None pkeys_subset: bool = False pkeys_overlap: bool = False pkeys_superset: bool = False pkeys_proper: bool = False def __init__(self, policy, **kwargs): super(IbpkeyconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) @property def pkeys(self) -> Optional[IbpkeyconRange]: return self._pkeys @pkeys.setter def pkeys(self, value: Optional[Tuple[int, int]]) -> None: if value is not None: pending_pkeys = IbpkeyconRange(*value) if pending_pkeys.low < 1 or pending_pkeys.high < 1: raise ValueError("Pkeys must be positive: {0.low:#x}-{0.high:#x}". format(pending_pkeys)) if pending_pkeys.low > 0xffff or pending_pkeys.high > 0xffff: raise ValueError("Pkeys maximum is 0xffff: {0.low:#x}-{0.high:#x}". format(pending_pkeys)) if pending_pkeys.low > pending_pkeys.high: raise ValueError( "The low pkey must be smaller than the high pkey: {0.low:#x}-{0.high:#x}". format(pending_pkeys)) self._pkeys = pending_pkeys else: self._pkeys = None @property def subnet_prefix(self) -> Optional[IPv6Address]: return self._subnet_prefix @subnet_prefix.setter def subnet_prefix(self, value: Optional[Union[str, IPv6Address]]) -> None: if value: self._subnet_prefix = IPv6Address(value) else: self._subnet_prefix = None def results(self) -> Iterable[Ibpkeycon]: """Generator which yields all matching ibpkeycons.""" self.log.info("Generating ibpkeycon results from {0.policy}".format(self)) self.log.debug("Subnet Prefix: {0.subnet_prefix}".format(self)) self.log.debug("Pkeys: {0.pkeys}, overlap: {0.pkeys_overlap}, " "subset: {0.pkeys_subset}, superset: {0.pkeys_superset}, " "proper: {0.pkeys_proper}".format(self)) self._match_context_debug(self.log) for pk in self.policy.ibpkeycons(): if self.subnet_prefix is not None and self.subnet_prefix != pk.subnet_prefix: continue if self.pkeys and not match_range( pk.pkeys, self.pkeys, self.pkeys_subset, self.pkeys_overlap, self.pkeys_superset, self.pkeys_proper): continue if not self._match_context(pk.context): continue yield pk setools-4.4.0/setools/infoflow.py000066400000000000000000000373011402045477700171120ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import itertools import logging from contextlib import suppress from typing import cast, Iterable, List, Mapping, Optional, Union import networkx as nx from networkx.exception import NetworkXError, NetworkXNoPath, NodeNotFound from .descriptors import EdgeAttrIntMax, EdgeAttrList from .permmap import PermissionMap from .policyrep import AVRule, SELinuxPolicy, TERuletype, Type __all__ = ['InfoFlowAnalysis'] InfoFlowPath = Iterable['InfoFlowStep'] class InfoFlowAnalysis: """Information flow analysis.""" _exclude: List[Type] _min_weight: int _perm_map: PermissionMap def __init__(self, policy: SELinuxPolicy, perm_map: PermissionMap, min_weight: int = 1, exclude: Optional[Iterable[Union[Type, str]]] = None, booleans: Optional[Mapping[str, bool]] = None) -> None: """ Parameters: policy The policy to analyze. perm_map The permission map or path to the permission map file. minweight The minimum permission weight to include in the analysis. (default is 1) exclude The types excluded from the information flow analysis. (default is none) booleans If None, all rules will be added to the analysis (default). otherwise it should be set to a dict with keys corresponding to boolean names and values of True/False. Any unspecified booleans will use the policy's default values. """ self.log = logging.getLogger(__name__) self.policy = policy self.min_weight = min_weight self.perm_map = perm_map self.exclude = exclude # type: ignore # https://github.com/python/mypy/issues/220 self.booleans = booleans self.rebuildgraph = True self.rebuildsubgraph = True self.G = nx.DiGraph() self.subG = self.G.copy() @property def min_weight(self) -> int: return self._min_weight @min_weight.setter def min_weight(self, weight: int) -> None: if not 1 <= weight <= 10: raise ValueError( "Min information flow weight must be an integer 1-10.") self._min_weight = weight self.rebuildsubgraph = True @property def perm_map(self) -> PermissionMap: return self._perm_map @perm_map.setter def perm_map(self, perm_map: PermissionMap) -> None: self._perm_map = perm_map self.rebuildgraph = True self.rebuildsubgraph = True @property def exclude(self) -> List[Type]: return self._exclude @exclude.setter def exclude(self, types: Optional[Iterable[Union[Type, str]]]) -> None: if types: self._exclude: List[Type] = [self.policy.lookup_type(t) for t in types] else: self._exclude = [] self.rebuildsubgraph = True def shortest_path(self, source: Type, target: Type) -> Iterable[InfoFlowPath]: """ Generator which yields one shortest path between the source and target types (there may be more). Parameters: source The source type. target The target type. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating one shortest information flow path from {0} to {1}...". format(s, t)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph # pylint: disable=unexpected-keyword-arg, no-value-for-parameter yield self.__generate_steps(nx.shortest_path(self.subG, source=s, target=t)) def all_paths(self, source: Union[Type, str], target: Union[Type, str], maxlen: int = 2) \ -> Iterable[InfoFlowPath]: """ Generator which yields all paths between the source and target up to the specified maximum path length. This algorithm tends to get very expensive above 3-5 steps, depending on the policy complexity. Parameters: source The source type. target The target type. maxlen Maximum length of paths. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ if maxlen < 1: raise ValueError("Maximum path length must be positive.") s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all information flow paths from {0} to {1}, max length {2}...". format(s, t, maxlen)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph for path in nx.all_simple_paths(self.subG, s, t, maxlen): yield self.__generate_steps(path) def all_shortest_paths(self, source: Union[Type, str], target: Union[Type, str]) \ -> Iterable[InfoFlowPath]: """ Generator which yields all shortest paths between the source and target types. Parameters: source The source type. target The target type. Yield: generator(steps) steps Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ s = self.policy.lookup_type(source) t = self.policy.lookup_type(target) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all shortest information flow paths from {0} to {1}...". format(s, t)) with suppress(NetworkXNoPath, NodeNotFound): # NodeNotFound: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight # NetworkXNoPath: no paths or the target type is # not in the graph for path in nx.all_shortest_paths(self.subG, s, t): yield self.__generate_steps(path) def infoflows(self, type_: Union[Type, str], out: bool = True) -> Iterable['InfoFlowStep']: """ Generator which yields all information flows in/out of a specified source type. Parameters: source The starting type. Keyword Parameters: out If true, information flows out of the type will be returned. If false, information flows in to the type will be returned. Default is true. Yield: generator(steps) steps A generator that returns the tuple of source, target, and rules for each information flow. """ s = self.policy.lookup_type(type_) if self.rebuildsubgraph: self._build_subgraph() self.log.info("Generating all information flows {0} {1}". format("out of" if out else "into", s)) with suppress(NetworkXError): # NetworkXError: the type is valid but not in graph, e.g. # excluded or disconnected due to min weight if out: flows = self.subG.out_edges(s) else: flows = self.subG.in_edges(s) for source, target in flows: yield InfoFlowStep(self.subG, source, target) def get_stats(self) -> str: # pragma: no cover """ Get the information flow graph statistics. Return: str """ if self.rebuildgraph: self._build_graph() return nx.info(self.G) # # Internal functions follow # def __generate_steps(self, path: List[Type]) -> InfoFlowPath: """ Generator which returns the source, target, and associated rules for each information flow step. Parameter: path A list of graph node names representing an information flow path. Yield: tuple(source, target, rules) source The source type for this step of the information flow. target The target type for this step of the information flow. rules The list of rules creating this information flow step. """ for s in range(1, len(path)): yield InfoFlowStep(self.subG, path[s - 1], path[s]) # # # Graph building functions # # # 1. _build_graph determines the flow in each direction for each TE # rule and then expands the rule. All information flows are # included in this main graph: memory is traded off for efficiency # as the main graph should only need to be rebuilt if permission # weights change. # 2. _build_subgraph derives a subgraph which removes all excluded # types (nodes) and edges (information flows) which are below the # minimum weight. This subgraph is rebuilt only if the main graph # is rebuilt or the minimum weight or excluded types change. def _build_graph(self) -> None: self.G.clear() self.G.name = "Information flow graph for {0}.".format(self.policy) self.perm_map.map_policy(self.policy) self.log.info("Building information flow graph from {0}...".format(self.policy)) for rule in self.policy.terules(): if rule.ruletype != TERuletype.allow: continue (rweight, wweight) = self.perm_map.rule_weight(cast(AVRule, rule)) for s, t in itertools.product(rule.source.expand(), rule.target.expand()): # only add flows if they actually flow # in or out of the source type type if s != t: if wweight: edge = InfoFlowStep(self.G, s, t, create=True) edge.rules.append(rule) edge.weight = wweight if rweight: edge = InfoFlowStep(self.G, t, s, create=True) edge.rules.append(rule) edge.weight = rweight self.rebuildgraph = False self.rebuildsubgraph = True self.log.info("Completed building information flow graph.") self.log.debug("Graph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.G), nx.number_of_edges(self.G))) def _build_subgraph(self) -> None: if self.rebuildgraph: self._build_graph() self.log.info("Building information flow subgraph...") self.log.debug("Excluding {0!r}".format(self.exclude)) self.log.debug("Min weight {0}".format(self.min_weight)) self.log.debug("Exclude disabled conditional policy: {0}".format( self.booleans is not None)) # delete excluded types from subgraph nodes = [n for n in self.G.nodes() if n not in self.exclude] self.subG = self.G.subgraph(nodes).copy() # delete edges below minimum weight. # no need if weight is 1, since that # does not exclude any edges. if self.min_weight > 1: delete_list = [] for s, t in self.subG.edges(): edge = InfoFlowStep(self.subG, s, t) if edge.weight < self.min_weight: delete_list.append(edge) self.subG.remove_edges_from(delete_list) if self.booleans is not None: delete_list = [] for s, t in self.subG.edges(): edge = InfoFlowStep(self.subG, s, t) # collect disabled rules rule_list = [] # pylint: disable=not-an-iterable for rule in edge.rules: if not rule.enabled(**self.booleans): rule_list.append(rule) deleted_rules: List[AVRule] = [] for rule in rule_list: if rule not in deleted_rules: edge.rules.remove(rule) deleted_rules.append(rule) if not edge.rules: delete_list.append(edge) self.subG.remove_edges_from(delete_list) self.rebuildsubgraph = False self.log.info("Completed building information flow subgraph.") self.log.debug("Subgraph stats: nodes: {0}, edges: {1}.".format( nx.number_of_nodes(self.subG), nx.number_of_edges(self.subG))) class InfoFlowStep: """ A graph edge. Also used for returning information flow steps. Parameters: graph The NetworkX graph. source The source type of the edge. target The target type of the edge. Keyword Parameters: create (T/F) create the edge if it does not exist. The default is False. """ rules = EdgeAttrList('rules') # use capacity to store the info flow weight so # we can use network flow algorithms naturally. # The weight for each edge is 1 since each info # flow step is no more costly than another # (see below add_edge() call) weight = EdgeAttrIntMax('capacity') def __init__(self, graph, source: Type, target: Type, create: bool = False) -> None: self.G = graph self.source = source self.target = target if not self.G.has_edge(source, target): if create: self.G.add_edge(source, target, weight=1) self.rules = None self.weight = None else: raise ValueError("InfoFlowStep does not exist in graph") def __getitem__(self, key): # This is implemented so this object can be used in NetworkX # functions that operate on (source, target) tuples if isinstance(key, slice): return [self._index_to_item(i) for i in range(* key.indices(2))] else: return self._index_to_item(key) def _index_to_item(self, index): """Return source or target based on index.""" if index == 0: return self.source elif index == 1: return self.target else: raise IndexError("Invalid index (edges only have 2 items): {0}".format(index)) setools-4.4.0/setools/initsidquery.py000066400000000000000000000056021402045477700200170ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .mixins import MatchContext, MatchName from .policyrep import InitialSID from .query import PolicyQuery class InitialSIDQuery(MatchName, MatchContext, PolicyQuery): """ Initial SID (Initial context) query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The Initial SID name to match. name_regex If true, regular expression matching will be used on the Initial SID name. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ def __init__(self, policy, **kwargs): super(InitialSIDQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[InitialSID]: """Generator which yields all matching initial SIDs.""" self.log.info("Generating initial SID results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_context_debug(self.log) for i in self.policy.initialsids(): if not self._match_name(i): continue if not self._match_context(i.context): continue yield i setools-4.4.0/setools/iomemconquery.py000066400000000000000000000111741402045477700201630ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional, Tuple from .mixins import MatchContext from .policyrep import Iomemcon, IomemconRange from .query import PolicyQuery from .util import match_range class IomemconQuery(MatchContext, PolicyQuery): """ Iomemcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: addr A 2-tuple of the memory addr range to match. (Set both to the same value for a single mem addr) addr_subset If true, the criteria will match if it is a subset of the iomemcon's range. addr_overlap If true, the criteria will match if it overlaps any of the iomemcon's range. addr_superset If true, the criteria will match if it is a superset of the iomemcon's range. addr_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _addr: Optional[IomemconRange] = None addr_subset: bool = False addr_overlap: bool = False addr_superset: bool = False addr_proper: bool = False @property def addr(self) -> Optional[IomemconRange]: return self._addr @addr.setter def addr(self, value: Optional[Tuple[int, int]]) -> None: if value: pending_addr = IomemconRange(*value) if pending_addr.low < 1 or pending_addr.high < 1: raise ValueError("Memory address must be positive: {0.low}-{0.high}". format(pending_addr)) if pending_addr.low > pending_addr.high: raise ValueError( "The low mem addr must be smaller than the high mem addr: {0.low}-{0.high}". format(pending_addr)) self._addr = pending_addr else: self._addr = None def __init__(self, policy, **kwargs) -> None: super(IomemconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Iomemcon]: """Generator which yields all matching iomemcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Address: {0.addr!r}, overlap: {0.addr_overlap}, " "subset: {0.addr_subset}, superset: {0.addr_superset}, " "proper: {0.addr_proper}".format(self)) self._match_context_debug(self.log) for iomemcon in self.policy.iomemcons(): if self.addr and not match_range( iomemcon.addr, self.addr, self.addr_subset, self.addr_overlap, self.addr_superset, self.addr_proper): continue if not self._match_context(iomemcon.context): continue yield iomemcon setools-4.4.0/setools/ioportconquery.py000066400000000000000000000112251402045477700203660ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional, Tuple from .mixins import MatchContext from .policyrep import Ioportcon, IoportconRange from .query import PolicyQuery from .util import match_range class IoportconQuery(MatchContext, PolicyQuery): """ Ioportcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ports A 2-tuple of the port range to match. (Set both to the same value for a single port) ports_subset If true, the criteria will match if it is a subset of the ioportcon's range. ports_overlap If true, the criteria will match if it overlaps any of the ioportcon's range. ports_superset If true, the criteria will match if it is a superset of the ioportcon's range. ports_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _ports: Optional[IoportconRange] = None ports_subset: bool = False ports_overlap: bool = False ports_superset: bool = False ports_proper: bool = False @property def ports(self) -> Optional[IoportconRange]: return self._ports @ports.setter def ports(self, value: Optional[Tuple[int, int]]) -> None: if value: pending_ports = IoportconRange(*value) if pending_ports.low < 1 or pending_ports.high < 1: raise ValueError("Port numbers must be positive: {0.low}-{0.high}". format(pending_ports)) if pending_ports.low > pending_ports.high: raise ValueError( "The low port must be smaller than the high port: {0.low}-{0.high}". format(pending_ports)) self._ports = pending_ports else: self._ports = None def __init__(self, policy, **kwargs) -> None: super(IoportconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Ioportcon]: """Generator which yields all matching ioportcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Ports: {0.ports!r}, overlap: {0.ports_overlap}, " "subset: {0.ports_subset}, superset: {0.ports_superset}, " "proper: {0.ports_proper}".format(self)) self._match_context_debug(self.log) for ioportcon in self.policy.ioportcons(): if self.ports and not match_range( ioportcon.ports, self.ports, self.ports_subset, self.ports_overlap, self.ports_superset, self.ports_proper): continue if not self._match_context(ioportcon.context): continue yield ioportcon setools-4.4.0/setools/mixins.py000066400000000000000000000167011402045477700165770ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=attribute-defined-outside-init,no-member import re from logging import Logger from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor, CriteriaPermissionSetDescriptor from .policyrep import Context from .util import match_in_set, match_regex, match_range, match_regex_or_set class MatchAlias: """Mixin for matching an object's aliases.""" alias = CriteriaDescriptor("alias_regex") alias_regex: bool = False def _match_alias_debug(self, log: Logger) -> None: """Emit log debugging info for alias matching.""" log.debug("Alias: {0.alias}, regex: {0.alias_regex}".format(self)) def _match_alias(self, obj): """ Match the alias criteria Parameter: obj An object with an alias generator method named "aliases" """ if not self.alias: # if there is no criteria, everything matches. return True return match_in_set(obj.aliases(), self.alias, self.alias_regex) class MatchContext: """ Mixin for matching contexts. Class attributes: user The user to match in the context. user_regex If true, regular expression matching will be used on the user. role The role to match in the context. role_regex If true, regular expression matching will be used on the role. type_ The type to match in the context. type_regex If true, regular expression matching will be used on the type. range_ The range to match in the context. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset on range matching operations. No effect if not using set operations. """ user = CriteriaDescriptor("user_regex", "lookup_user") user_regex: bool = False role = CriteriaDescriptor("role_regex", "lookup_role") role_regex: bool = False type_ = CriteriaDescriptor("type_regex", "lookup_type") type_regex: bool = False range_ = CriteriaDescriptor(lookup_function="lookup_range") range_overlap: bool = False range_subset: bool = False range_superset: bool = False range_proper: bool = False def _match_context_debug(self, log: Logger): """Emit log debugging info for context matching.""" log.debug("User: {0.user!r}, regex: {0.user_regex}".format(self)) log.debug("Role: {0.role!r}, regex: {0.role_regex}".format(self)) log.debug("Type: {0.type_!r}, regex: {0.type_regex}".format(self)) log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) def _match_context(self, context: Context) -> bool: """ Match the context criteria. Parameter: obj An object with context attributes "user", "role", "type_" and "range_". """ if self.user and not match_regex( context.user, self.user, self.user_regex): return False if self.role and not match_regex( context.role, self.role, self.role_regex): return False if self.type_ and not match_regex( context.type_, self.type_, self.type_regex): return False if self.range_ and not match_range( context.range_, self.range_, self.range_subset, self.range_overlap, self.range_superset, self.range_proper): return False return True class MatchName: """Mixin for matching an object's name with alias dereferencing.""" name = CriteriaDescriptor("name_regex") name_regex: bool = False alias_deref: bool = False def _match_name_debug(self, log: Logger) -> None: """Log debugging messages for name matching.""" log.debug("Name: {0.name!r}, regex: {0.name_regex}, deref: {0.alias_deref}".format(self)) def _match_name(self, obj): """Match the object to the name criteria.""" if not self.name: # if there is no criteria, everything matches. return True if self.alias_deref: return match_regex(obj, self.name, self.name_regex) or \ match_in_set(obj.aliases(), self.name, self.name_regex) else: return match_regex(obj, self.name, self.name_regex) class MatchObjClass: """Mixin for matching an object's class.""" tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex: bool = False def _match_object_class_debug(self, log: Logger) -> None: """Emit log debugging info for permission matching.""" log.debug("Class: {0.tclass!r}, regex: {0.tclass_regex}".format(self)) def _match_object_class(self, obj): """ Match the object class criteria Parameter: obj An object with an object class attribute named "tclass" """ if not self.tclass: # if there is no criteria, everything matches. return True elif self.tclass_regex: return bool(self.tclass.search(str(obj.tclass))) else: return obj.tclass in self.tclass class MatchPermission: """Mixin for matching an object's permissions.""" perms = CriteriaPermissionSetDescriptor(name_regex="perms_regex") perms_equal: bool = False perms_regex: bool = False perms_subset: bool = False def _match_perms_debug(self, log: Logger): """Emit log debugging info for permission matching.""" log.debug("Perms: {0.perms!r}, regex: {0.perms_regex}, eq: {0.perms_equal}, " "subset: {0.perms_subset!r}".format(self)) def _match_perms(self, obj): """ Match the permission criteria Parameter: obj An object with a permission set class attribute named "perms" """ if not self.perms: # if there is no criteria, everything matches. return True if self.perms_subset: return obj.perms >= self.perms else: return match_regex_or_set(obj.perms, self.perms, self.perms_equal, self.perms_regex) setools-4.4.0/setools/mlsrulequery.py000066400000000000000000000113271402045477700200400ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchObjClass from .policyrep import MLSRule, MLSRuletype from .query import PolicyQuery from .util import match_indirect_regex, match_range class MLSRuleQuery(MatchObjClass, PolicyQuery): """ Query MLS rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source type/attribute to match. source_regex If true, regular expression matching will be used on the source type/attribute. target The name of the target type/attribute to match. target_regex If true, regular expression matching will be used on the target type/attribute. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. """ ruletype = CriteriaSetDescriptor(enum_class=MLSRuletype) source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") source_regex: bool = False source_indirect: bool = True target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") target_regex: bool = False target_indirect: bool = True tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex: bool = False default = CriteriaDescriptor(lookup_function="lookup_range") default_overlap: bool = False default_subset: bool = False default_superset: bool = False default_proper: bool = False def __init__(self, policy, **kwargs) -> None: super(MLSRuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[MLSRule]: """Generator which yields all matching MLS rules.""" self.log.info("Generating MLS rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}, overlap: {0.default_overlap}, " "subset: {0.default_subset}, superset: {0.default_superset}, " "proper: {0.default_proper}".format(self)) for rule in self.policy.mlsrules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source type # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # if not self._match_object_class(rule): continue # # Matching on range # if self.default and not match_range( rule.default, self.default, self.default_subset, self.default_overlap, self.default_superset, self.default_proper): continue # if we get here, we have matched all available criteria yield rule setools-4.4.0/setools/netifconquery.py000066400000000000000000000060251402045477700201610ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .mixins import MatchContext, MatchName from .policyrep import Netifcon from .query import PolicyQuery from .util import match_regex class NetifconQuery(MatchContext, MatchName, PolicyQuery): """ Network interface context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the network interface to match. name_regex If true, regular expression matching will be used for matching the name. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ def __init__(self, policy, **kwargs) -> None: super(NetifconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Netifcon]: """Generator which yields all matching netifcons.""" self.log.info("Generating netifcon results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_context_debug(self.log) for netif in self.policy.netifcons(): if self.name and not match_regex( netif.netif, self.name, self.name_regex): continue if not self._match_context(netif.context): continue yield netif setools-4.4.0/setools/nodeconquery.py000066400000000000000000000110321402045477700177730ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2017, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import ipaddress import logging from socket import AF_INET, AF_INET6 from typing import Iterable, Optional, Union from .mixins import MatchContext from .policyrep import Nodecon, NodeconIPVersion from .query import PolicyQuery AnyIPNetwork = Union[ipaddress.IPv4Network, ipaddress.IPv6Network] class NodeconQuery(MatchContext, PolicyQuery): """ Query nodecon statements. Parameter: policy The policy to query. Keyword Parameters/Class attributes: network The IPv4/IPv6 address or IPv4/IPv6 network address with netmask, e.g. 192.168.1.0/255.255.255.0 or "192.168.1.0/24". network_overlap If true, the net will match if it overlaps with the nodecon's network instead of equality. ip_version The IP version of the nodecon to match. (socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6) user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _network: Optional[AnyIPNetwork] = None network_overlap: bool = False _ip_version: Optional[NodeconIPVersion] = None @property def ip_version(self) -> Optional[NodeconIPVersion]: return self._ip_version @ip_version.setter def ip_version(self, value: Optional[Union[str, NodeconIPVersion]]) -> None: if value: self._ip_version = NodeconIPVersion.lookup(value) else: self._ip_version = None @property def network(self) -> Optional[AnyIPNetwork]: return self._network @network.setter def network(self, value: Optional[Union[str, AnyIPNetwork]]) -> None: if value: self._network = ipaddress.ip_network(value) else: self._network = None def __init__(self, policy, **kwargs) -> None: super(NodeconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Nodecon]: """Generator which yields all matching nodecons.""" self.log.info("Generating nodecon results from {0.policy}".format(self)) self.log.debug("Network: {0.network!r}, overlap: {0.network_overlap}".format(self)) self.log.debug("IP Version: {0.ip_version!r}".format(self)) self._match_context_debug(self.log) for nodecon in self.policy.nodecons(): if self.network: if self.network_overlap: if not self.network.overlaps(nodecon.network): # type: ignore continue else: if not nodecon.network == self.network: continue if self.ip_version and self.ip_version != nodecon.ip_version: continue if not self._match_context(nodecon.context): continue yield nodecon setools-4.4.0/setools/objclassquery.py000066400000000000000000000076211402045477700201570ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from contextlib import suppress from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .exception import NoCommon from .mixins import MatchName from .policyrep import ObjClass from .query import PolicyQuery from .util import match_regex, match_regex_or_set class ObjClassQuery(MatchName, PolicyQuery): """ Query object classes. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the object set to match. name_regex If true, regular expression matching will be used for matching the name. common The name of the inherited common to match. common_regex If true, regular expression matching will be used for matching the common name. perms The permissions to match. perms_equal If true, only commons with permission sets that are equal to the criteria will match. Otherwise, any intersection will match. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. comparison will not be used. perms_indirect If false, permissions inherited from a common permission set not will be evaluated. Default is true. """ common = CriteriaDescriptor("common_regex", "lookup_common") common_regex: bool = False perms = CriteriaSetDescriptor("perms_regex") perms_equal: bool = False perms_indirect: bool = True perms_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(ObjClassQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[ObjClass]: """Generator which yields all matching object classes.""" self.log.info("Generating object class results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Common: {0.common!r}, regex: {0.common_regex}".format(self)) self.log.debug("Perms: {0.perms}, regex: {0.perms_regex}, " "eq: {0.perms_equal}, indirect: {0.perms_indirect}".format(self)) for class_ in self.policy.classes(): if not self._match_name(class_): continue if self.common: try: if not match_regex( class_.common, self.common, self.common_regex): continue except NoCommon: continue if self.perms: perms = class_.perms if self.perms_indirect: with suppress(NoCommon): perms |= class_.common.perms if not match_regex_or_set( perms, self.perms, self.perms_equal, self.perms_regex): continue yield class_ setools-4.4.0/setools/pcideviceconquery.py000066400000000000000000000063171402045477700210130ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional from .mixins import MatchContext from .policyrep import Pcidevicecon from .query import PolicyQuery class PcideviceconQuery(MatchContext, PolicyQuery): """ Pcidevicecon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: device A single PCI device ID. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _device: Optional[int] = None @property def device(self) -> Optional[int]: return self._device @device.setter def device(self, value: Optional[int]) -> None: if value: if value < 1: raise ValueError("PCI device ID must be positive: {0}".format(value)) self._device = value else: self._device = None def __init__(self, policy, **kwargs) -> None: super(PcideviceconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Pcidevicecon]: """Generator which yields all matching pcidevicecons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("Device ID: {0.device!r}".format(self)) self._match_context_debug(self.log) for pcidevicecon in self.policy.pcidevicecons(): if self.device and self.device != pcidevicecon.device: continue if not self._match_context(pcidevicecon.context): continue yield pcidevicecon setools-4.4.0/setools/perm_map000066400000000000000000002562471402045477700164540ustar00rootroot00000000000000# This is a permission map file for use in policy analysis. This # file maps object permissions (read, getattr, setattr, ..., etc.) # for an object class, to exactly one of the following: read, write, # both, or none. This file may be edited as long as the specific # syntax rules are obeyed. # # For each object class, there is a set of object permissions that are # individually mapped to read, write, both, or none. If a new object # class is added, make sure that the current number of object classes # is increased. # # The syntax for an object class definition is: # class # # This is followed by each permission and its individual mapping to one # of the following: # # r = Read # w = Write # n = None # b = Both # # Additionally, you can choose to follow the mapping with an optional # permission weight value from 1 (less importance) to 10 (higher importance). # 10 is the default weight value if one is not provided. # # Look to the examples below for further clarification. # # Number of object classes. 129 class netlink_audit_socket 28 nlmsg_relay w 10 nlmsg_tty_audit w 10 nlmsg_readpriv r 10 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class tcp_socket 28 acceptfrom r 1 connectto w 1 node_bind n 1 newconn w 1 name_connect w 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class msgq 10 enqueue w 1 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class x_property 7 append w 10 create w 1 write w 10 destroy w 1 getattr r 7 setattr w 7 read r 10 class db_procedure 9 execute r 1 install w 10 entrypoint r 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class dir 26 rmdir b 1 audit_access r 1 remove_name w 1 add_name w 5 reparent w 1 execmod n 1 search r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class peer 1 recv r 10 class blk_file 21 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class chr_file 23 audit_access r 1 entrypoint r 1 execmod n 1 execute_no_trans r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class db_table 11 select n 1 delete w 1 update w 10 insert w 10 lock n 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class db_tuple 7 select n 1 delete w 1 update w 10 relabelfrom r 1 insert w 10 use r 10 relabelto w 1 class dbus 2 acquire_svc b 1 send_msg w 10 class ipc 9 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class lnk_file 21 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 1 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class process 31 getcap r 3 setcap w 1 sigstop w 1 sigchld w 1 share b 1 execheap n 1 setcurrent w 1 setfscreate w 1 setkeycreate w 1 siginh n 1 dyntransition w 10 transition w 5 fork n 1 getsession r 1 noatsecure n 1 sigkill w 1 signull n 1 setrlimit n 1 getattr r 1 getsched r 1 setexec w 1 setsched w 1 getpgid r 1 setpgid w 5 ptrace b 10 execstack n 1 rlimitinh n 1 setsockcreate w 1 signal w 5 execmem n 1 getrlimit r 1 class capability2 6 mac_override n 1 mac_admin n 1 syslog n 1 block_suspend n 1 wake_alarm n 1 audit_read n 1 class fd 1 use b 1 class packet 7 forward_out w 10 flow_out w 10 send w 10 recv r 10 forward_in r 10 relabelto w 3 flow_in r 10 class socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class fifo_file 21 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class file 23 audit_access r 1 entrypoint r 1 execmod n 1 execute_no_trans r 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 5 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class node 11 rawip_recv r 10 tcp_recv r 10 udp_recv r 10 rawip_send w 10 tcp_send w 10 udp_send w 10 dccp_recv r 10 dccp_send w 10 enforce_dest n 1 sendto w 10 recvfrom r 10 class x_cursor 7 create w 1 write w 10 destroy w 1 getattr r 7 setattr w 7 read r 10 use r 1 class x_server 6 record r 10 getattr r 7 grab w 1 setattr w 7 manage w 10 debug b 10 class db_view 7 expand w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr w 5 relabelto w 1 class netlink_nflog_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class key 7 create w 10 write w 10 view r 7 link w 7 setattr w 7 read r 10 search r 5 class netlink_tcpdiag_socket 25 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class unix_stream_socket 26 acceptfrom r 1 connectto w 1 newconn w 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_synthetic_event 2 send w 10 receive r 10 class db_database 11 access b 10 set_param w 7 load_module r 10 get_param r 7 install_module r 10 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class db_language 8 execute w 1 implement w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr w 5 relabelto w 1 class kernel_service 2 create_files_as n 1 use_as_override n 1 class netlink_route_socket 25 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_extension 2 use r 1 query r 5 class db_sequence 9 set_value w 10 get_value r 10 next_value w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 5 setattr r 5 relabelto w 1 class shm 10 lock w 1 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class x_resource 2 write w 10 read r 10 class netlink_selinux_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class capability 32 setfcap n 1 setpcap n 1 fowner n 1 sys_boot n 1 sys_tty_config n 1 net_raw n 1 sys_admin n 1 sys_chroot n 1 sys_module n 1 sys_rawio n 1 dac_override n 1 ipc_owner n 1 kill n 1 dac_read_search n 1 sys_pacct n 1 net_broadcast n 1 net_bind_service n 1 sys_nice n 1 sys_time n 1 fsetid n 1 mknod n 1 setgid n 1 setuid n 1 lease n 1 net_admin n 1 audit_write n 1 linux_immutable n 1 sys_ptrace n 1 audit_control n 1 ipc_lock n 1 sys_resource n 1 chown n 1 class netlink_ip6fw_socket 25 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class dccp_socket 25 node_bind n 1 name_connect w 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_firewall_socket 25 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class sock_file 21 audit_access r 1 execmod n 1 open n 1 append w 10 create w 1 execute r 1 write w 10 relabelfrom r 10 link w 1 unlink w 1 ioctl n 1 getattr r 7 setattr w 7 read r 10 rename w 1 lock n 1 relabelto w 10 mounton b 1 quotaon b 1 swapon b 1 map n 1 class unix_dgram_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_kobject_uevent_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class db_blob 10 write w 10 export r 10 import w 10 read r 10 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class filesystem 10 associate n 1 quotaget r 1 relabelfrom r 10 transition w 1 getattr r 1 quotamod w 1 mount w 1 remount w 1 unmount w 1 relabelto w 10 class netlink_xfrm_socket 25 nlmsg_write w 10 nlmsg_read r 10 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_device 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus r 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class db_schema 9 remove_name w 1 add_name w 5 search r 5 drop w 1 create w 1 relabelfrom w 1 getattr r 5 setattr w 5 relabelto r 1 class netlink_dnrt_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_client 4 destroy w 1 getattr r 7 setattr w 7 manage w 10 class x_gc 5 create w 1 destroy w 1 getattr r 7 setattr w 7 use r 1 class context 2 contains n 1 translate n 1 class nscd 10 shmemserv r 7 gethost r 7 getstat r 7 getgrp r 7 shmemhost r 7 shmempwd r 7 getpwd r 7 getserv r 7 shmemgrp r 7 admin w 5 class passwd 5 chfn w 5 crontab w 5 passwd w 1 chsh w 5 rootok n 1 class x_event 2 send w 10 receive r 10 class x_font 6 create w 1 destroy w 1 add_glyph w 1 remove_glyph w 1 getattr r 7 use r 1 class key_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netif 10 rawip_recv r 10 tcp_recv r 10 udp_recv r 10 rawip_send w 10 egress w 10 ingress r 10 tcp_send w 10 udp_send w 10 dccp_recv r 10 dccp_send w 10 class packet_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class memprotect 1 mmap_zero n 1 class msg 2 send w 10 receive r 10 class tun_socket 24 attach_queue w 5 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class udp_socket 24 node_bind n 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class appletalk_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 1 setattr w 1 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_colormap 10 add_color w 10 create w 1 write w 10 destroy w 1 install w 1 getattr r 7 read r 10 use r 1 remove_color w 10 uninstall w 1 class x_screen 8 show_cursor w 1 hide_cursor w 1 saver_show w 1 getattr r 7 setattr w 7 saver_hide w 1 saver_getattr r 7 saver_setattr w 7 class rawip_socket 24 node_bind n 1 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 1 setattr w 1 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_application_data 3 paste w 10 paste_after_confirm w 10 copy r 10 class association 4 setcontext w 3 sendto w 10 recvfrom r 10 polmatch r 1 class x_selection 4 write w 10 getattr r 7 setattr w 7 read r 10 class db_column 9 select r 10 update w 10 insert w 1 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 class netlink_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x_drawable 19 get_property r 7 list_property r 7 set_property w 7 add_child w 1 override n 1 blend w 1 send w 10 create w 1 hide w 1 receive r 10 write w 10 show w 1 destroy w 1 list_child r 7 getattr r 7 setattr w 7 read r 10 manage w 10 remove_child w 1 class sem 9 associate n 1 create w 1 write w 10 unix_read r 3 destroy w 1 getattr r 1 setattr w 1 read r 10 unix_write w 3 class system 14 module_request n 1 ipc_info n 1 syslog_read n 1 syslog_console n 1 syslog_mod n 1 reload w 1 halt n 1 reboot n 1 status r 5 enable n 1 disable n 1 start w 5 stop w 5 module_load w 10 class x_keyboard 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus w 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class security 13 compute_member n 1 compute_user n 1 compute_create n 1 setenforce n 1 check_context n 1 setcheckreqprot n 1 compute_relabel n 1 setbool n 1 load_policy n 1 read_policy n 1 setsecparam n 1 compute_av n 1 validate_trans n 1 class x_pointer 19 get_property r 7 list_property r 7 set_property w 7 add w 1 setfocus w 1 create w 1 freeze w 1 getfocus w 1 remove w 1 write w 10 force_cursor w 1 destroy w 1 bell w 1 getattr r 7 grab w 1 setattr w 7 read r 10 manage w 10 use r 1 class binder 4 transfer w 3 call w 10 set_context_mgr w 1 impersonate n 1 class netlink_connector_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_netfilter_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_iscsi_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class db_exception 7 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 use r 1 class netlink_rdma_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_generic_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netlink_scsitransport_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class service 6 status r 1 start w 1 disable n 1 enable n 1 reload w 1 stop w 1 class netlink_crypto_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class db_datatype 7 drop w 1 create w 1 relabelfrom r 1 getattr r 7 setattr w 7 relabelto w 1 use r 1 class netlink_fib_lookup_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class cap_userns 32 setfcap n 1 setpcap n 1 fowner n 1 sys_boot n 1 sys_tty_config n 1 net_raw n 1 sys_admin n 1 sys_chroot n 1 sys_module n 1 sys_rawio n 1 dac_override n 1 ipc_owner n 1 kill n 1 dac_read_search n 1 sys_pacct n 1 net_broadcast n 1 net_bind_service n 1 sys_nice n 1 sys_time n 1 fsetid n 1 mknod n 1 setgid n 1 setuid n 1 lease n 1 net_admin n 1 audit_write n 1 linux_immutable n 1 sys_ptrace n 1 audit_control n 1 ipc_lock n 1 sys_resource n 1 chown n 1 class cap2_userns 6 mac_override n 1 mac_admin n 1 syslog n 1 block_suspend n 1 wake_alarm n 1 audit_read n 1 class ax25_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class ipx_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class netrom_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class x25_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class rose_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class decnet_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class atmsvc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class rds_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class irda_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class pppox_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class llc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class can_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class tipc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class bluetooth_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class iucv_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class rxrpc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class isdn_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class phonet_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class ieee802154_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class caif_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class alg_socket 23 append w 10 bind w 1 connect n 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class nfc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class vsock_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class kcm_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class qipcrtr_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class smc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class sctp_socket 26 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 node_bind n 1 association w 1 name_connect w 10 class atmpvc_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 class icmp_socket 24 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 node_bind n 1 class process2 2 nnp_transition w 1 nosuid_transition w 1 class bpf 5 prog_run w 10 map_read r 10 map_write w 10 prog_load w 10 map_create w 10 class infiniband_endport 1 manage_subnet w 10 class infiniband_pkey 1 access b 10 class xdp_socket 23 append w 10 bind w 1 connect w 1 create w 1 write w 10 relabelfrom r 10 ioctl n 1 name_bind n 1 sendto w 10 recv_msg r 10 send_msg w 10 getattr r 7 setattr w 7 accept r 1 getopt r 1 read r 10 setopt w 1 shutdown w 1 recvfrom r 10 lock n 1 relabelto w 10 listen r 1 map n 1 setools-4.4.0/setools/permmap.py000066400000000000000000000415041402045477700167300ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from collections import OrderedDict from contextlib import suppress from typing import cast, Dict, Iterable, NamedTuple, Optional, Union import pkg_resources from . import exception from .descriptors import PermissionMapDescriptor from .policyrep import AVRule, SELinuxPolicy, TERuletype INFOFLOW_DIRECTIONS = ("r", "w", "b", "n", "u") MIN_WEIGHT = 1 MAX_WEIGHT = 10 class RuleWeight(NamedTuple): """The read and write weights for a rule, given all of its permissions.""" read: int write: int # # Settings validation functions for Mapping descriptors # def validate_weight(weight: int) -> int: if not MIN_WEIGHT <= weight <= MAX_WEIGHT: raise ValueError("Permission weights must be 1-10: {0}".format(weight)) return weight def validate_direction(direction: str) -> str: if direction not in INFOFLOW_DIRECTIONS: raise ValueError("Invalid information flow direction: {0}".format(direction)) return direction # Internal data structure for permission map MapStruct = Dict[str, Dict[str, Dict[str, Union[bool, str, int]]]] class Mapping: """A mapping for a permission in the permission map.""" weight = PermissionMapDescriptor("weight", validate_weight) direction = PermissionMapDescriptor("direction", validate_direction) enabled = PermissionMapDescriptor("enabled", bool) class_: str perm: str def __init__(self, perm_map: MapStruct, classname: str, permission: str, create: bool = False) -> None: self._perm_map = perm_map self.class_ = classname self.perm = permission if create: if classname not in self._perm_map: self._perm_map[classname] = OrderedDict() self._perm_map[classname][permission] = {'direction': 'u', 'weight': 1, 'enabled': True} else: if classname not in self._perm_map: raise exception.UnmappedClass("{0} is not mapped.".format(classname)) if permission not in self._perm_map[classname]: raise exception.UnmappedPermission("{0}:{1} is not mapped.". format(classname, permission)) def __lt__(self, other) -> bool: if self.class_ == other.class_: return self.perm < other.perm return self.class_ < other.class_ class PermissionMap: """Permission Map for information flow analysis.""" def __init__(self, permmapfile: Optional[str] = None) -> None: """ Parameter: permmapfile The path to the permission map to load. """ self.log = logging.getLogger(__name__) self._permmap: MapStruct = OrderedDict() self._permmapfile: str if permmapfile: self.load(permmapfile) else: distro = pkg_resources.get_distribution("setools") # pylint: disable=no-member path = "{0}/setools/perm_map".format(distro.location) self.load(path) def __str__(self) -> str: return self._permmapfile def __deepcopy__(self, memo) -> 'PermissionMap': newobj = PermissionMap.__new__(PermissionMap) newobj.log = self.log newobj.permmap = copy.deepcopy(self._permmap) newobj.permmapfile = self._permmapfile memo[id(self)] = newobj return newobj def __iter__(self) -> Iterable[Mapping]: for cls in self.classes(): for mapping in self.perms(cls): yield mapping def load(self, permmapfile: str) -> None: """ Parameter: permmapfile The path to the permission map to load. """ self.log.info("Opening permission map \"{0}\"".format(permmapfile)) # state machine # 1 = read number of classes # 2 = read class name and number of perms # 3 = read perms with open(permmapfile, "r") as mapfile: total_perms = 0 class_count = 0 num_classes = 0 state = 1 self._permmap.clear() for line_num, line in enumerate(mapfile, start=1): entry = line.split() if len(entry) == 0 or entry[0][0] == '#': continue if state == 1: try: num_classes = int(entry[0]) except ValueError as ex: raise exception.PermissionMapParseError( "{0}:{1}:Invalid number of classes: {2}". format(permmapfile, line_num, entry[0])) from ex if num_classes < 1: raise exception.PermissionMapParseError( "{0}:{1}:Number of classes must be positive: {2}". format(permmapfile, line_num, entry[0])) state = 2 elif state == 2: if len(entry) != 3 or entry[0] != "class": raise exception.PermissionMapParseError( "{0}:{1}:Invalid class declaration: {2}". format(permmapfile, line_num, entry)) class_name = str(entry[1]) try: num_perms = int(entry[2]) except ValueError as ex: raise exception.PermissionMapParseError( "{0}:{1}:Invalid number of permissions: {2}". format(permmapfile, line_num, entry[2])) from ex if num_perms < 1: raise exception.PermissionMapParseError( "{0}:{1}:Number of permissions must be positive: {2}". format(permmapfile, line_num, entry[2])) class_count += 1 if class_count > num_classes: raise exception.PermissionMapParseError( "{0}:{1}:Extra class found: {2}". format(permmapfile, line_num, class_name)) self._permmap[class_name] = OrderedDict() perm_count = 0 state = 3 elif state == 3: perm_name = str(entry[0]) flow_direction = str(entry[1]) if flow_direction not in INFOFLOW_DIRECTIONS: raise exception.PermissionMapParseError( "{0}:{1}:Invalid information flow direction: {2}". format(permmapfile, line_num, entry[1])) try: weight = int(entry[2]) except ValueError as ex: raise exception.PermissionMapParseError( "{0}:{1}:Invalid permission weight: {2}". format(permmapfile, line_num, entry[2])) from ex if not MIN_WEIGHT <= weight <= MAX_WEIGHT: raise exception.PermissionMapParseError( "{0}:{1}:Permission weight must be {3}-{4}: {2}". format(permmapfile, line_num, entry[2], MIN_WEIGHT, MAX_WEIGHT)) self.log.debug("Read {0}:{1} {2} {3}".format( class_name, perm_name, flow_direction, weight)) if flow_direction == 'u': self.log.info("Permission {0}:{1} is unmapped.".format( class_name, perm_name)) mapping = Mapping(self._permmap, class_name, perm_name, create=True) mapping.direction = flow_direction mapping.weight = weight total_perms += 1 perm_count += 1 if perm_count >= num_perms: state = 2 self._permmapfile = permmapfile self.log.info("Successfully opened permission map \"{0}\"".format(permmapfile)) self.log.debug("Read {0} classes and {1} total permissions.".format( class_count, total_perms)) def save(self, permmapfile: str) -> None: """ Save the permission map to the specified path. Existing files will be overwritten. Parameter: permmapfile The path to write the permission map. """ with open(permmapfile, "w") as mapfile: self.log.info("Writing permission map to \"{0}\"".format(permmapfile)) mapfile.write("{0}\n\n".format(len(self._permmap))) for classname, perms in self._permmap.items(): mapfile.write("class {0} {1}\n".format(classname, len(perms))) for permname, settings in perms.items(): direction = cast(str, settings['direction']) weight = cast(int, settings['weight']) assert MIN_WEIGHT <= weight <= MAX_WEIGHT, \ "{0}:{1} weight is out of range ({2}). This is an SETools bug.".format( classname, permname, weight) assert direction in INFOFLOW_DIRECTIONS, \ "{0}:{1} flow direction ({2}) is invalid. This is an SETools bug.".format( classname, permname, direction) if direction == 'u': self.log.warning("Warning: permission {0} in class {1} is unmapped.".format( permname, classname)) mapfile.write("{0:>20} {1:>9} {2:>9}\n".format(permname, direction, weight)) mapfile.write("\n") self.log.info("Successfully wrote permission map to \"{0}\"".format(permmapfile)) def classes(self) -> Iterable[str]: """ Generate class names in the permission map. Yield: class An object class name. """ yield from self._permmap.keys() def perms(self, class_: str) -> Iterable[Mapping]: """ Generate permission mappings for the specified class. Parameter: class_ An object class name. Yield: Mapping A permission's complete map (weight, direction, enabled) """ try: for perm in self._permmap[class_].keys(): yield Mapping(self._permmap, class_, perm) except KeyError as ex: raise exception.UnmappedClass("{0} is not mapped.".format(class_)) from ex def mapping(self, class_: str, perm: str) -> Mapping: """Retrieve a specific permission's mapping.""" return Mapping(self._permmap, class_, perm) def exclude_class(self, class_: str) -> None: """ Exclude all permissions in an object class for calculating rule weights. Parameter: class_ The object class to exclude. Exceptions: UnmappedClass The specified object class is not mapped. """ for perm in self.perms(class_): perm.enabled = False def exclude_permission(self, class_: str, permission: str) -> None: """ Exclude a permission for calculating rule weights. Parameter: class_ The object class of the permission. permission The permission name to exclude. Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self._permmap, class_, permission).enabled = False def include_class(self, class_: str) -> None: """ Include all permissions in an object class for calculating rule weights. Parameter: class_ The object class to include. Exceptions: UnmappedClass The specified object class is not mapped. """ for perm in self.perms(class_): perm.enabled = True def include_permission(self, class_: str, permission: str) -> None: """ Include a permission for calculating rule weights. Parameter: class_ The object class of the permission. permission The permission name to include. Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self._permmap, class_, permission).enabled = True def map_policy(self, policy: SELinuxPolicy) -> None: """Create mappings for all classes and permissions in the specified policy.""" for class_ in policy.classes(): class_name = str(class_) if class_name not in self._permmap: self.log.debug("Adding unmapped class {0} from {1}".format(class_name, policy)) self._permmap[class_name] = OrderedDict() perms = class_.perms with suppress(exception.NoCommon): perms |= class_.common.perms for perm_name in perms: if perm_name not in self._permmap[class_name]: self.log.debug("Adding unmapped permission {0} in {1} from {2}". format(perm_name, class_name, policy)) Mapping(self._permmap, class_name, perm_name, create=True) def rule_weight(self, rule: AVRule) -> RuleWeight: """ Get the type enforcement rule's information flow read and write weights. Parameter: rule A type enforcement rule. Return: Tuple(read_weight, write_weight) read_weight The type enforcement rule's read weight. write_weight The type enforcement rule's write weight. """ write_weight = 0 read_weight = 0 class_name = str(rule.tclass) if rule.ruletype != TERuletype.allow: raise exception.RuleTypeError("{0} rules cannot be used for calculating a weight". format(rule.ruletype)) # iterate over the permissions and determine the # weight of the rule in each direction. The result # is the largest-weight permission in each direction for perm_name in rule.perms: mapping = Mapping(self._permmap, class_name, perm_name) if not mapping.enabled: continue if mapping.direction == "r": read_weight = max(read_weight, mapping.weight) elif mapping.direction == "w": write_weight = max(write_weight, mapping.weight) elif mapping.direction == "b": read_weight = max(read_weight, mapping.weight) write_weight = max(write_weight, mapping.weight) return RuleWeight(read_weight, write_weight) def set_direction(self, class_: str, permission: str, direction: str) -> None: """ Set the information flow direction of a permission. Parameter: class_ The object class of the permission. permission The permission name. direction The information flow direction the permission (r/w/b/n). Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self._permmap, class_, permission).direction = direction def set_weight(self, class_: str, permission: str, weight: int) -> None: """ Set the weight of a permission. Parameter: class_ The object class of the permission. permission The permission name. weight The weight of the permission (1-10). Exceptions: UnmappedClass The specified object class is not mapped. UnmappedPermission The specified permission is not mapped for the object class. """ Mapping(self._permmap, class_, permission).weight = weight setools-4.4.0/setools/pirqconquery.py000066400000000000000000000061471402045477700200340ustar00rootroot00000000000000# Derived from portconquery.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable, Optional from .mixins import MatchContext from .policyrep import Pirqcon from .query import PolicyQuery class PirqconQuery(MatchContext, PolicyQuery): """ Pirqcon context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: irq A single IRQ value. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _irq: Optional[int] = None @property def irq(self) -> Optional[int]: return self._irq @irq.setter def irq(self, value: Optional[int]) -> None: if value: if value < 1: raise ValueError("The IRQ must be positive: {0}".format(value)) self._irq = value else: self._irq = None def __init__(self, policy, **kwargs) -> None: super(PirqconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Pirqcon]: """Generator which yields all matching pirqcons.""" self.log.info("Generating results from {0.policy}".format(self)) self.log.debug("IRQ: {0.irq!r}".format(self)) self._match_context_debug(self.log) for pirqcon in self.policy.pirqcons(): if self.irq and self.irq != pirqcon.irq: continue if not self._match_context(pirqcon.context): continue yield pirqcon setools-4.4.0/setools/polcapquery.py000066400000000000000000000033651402045477700176360ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .mixins import MatchName from .policyrep import PolicyCapability from .query import PolicyQuery class PolCapQuery(MatchName, PolicyQuery): """ Query SELinux policy capabilities Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the policy capability to match. name_regex If true, regular expression matching will be used for matching the name. """ def __init__(self, policy, **kwargs) -> None: super(PolCapQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[PolicyCapability]: """Generator which yields all matching policy capabilities.""" self.log.info("Generating policy capability results from {0.policy}".format(self)) self._match_name_debug(self.log) for cap in self.policy.polcaps(): if not self._match_name(cap): continue yield cap setools-4.4.0/setools/policyrep.pyi000066400000000000000000001542161402045477700174530ustar00rootroot00000000000000# This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import Any, Callable, Dict, FrozenSet, Iterable, Iterator, List, NamedTuple, \ NoReturn, Optional, Set, Tuple, Union import enum import ipaddress import setools.exception import typing import weakref AnyConstraint = Union["Constraint", "Validatetrans"] AnyDefault = Union["Default", "DefaultRange"] AnyRBACRule = Union["RoleAllow", "RoleTransition"] AnyTERule = Union["AVRule", "AVRuleXperm", "TERule", "FileNameTERule"] SELINUX_SIDNAMES: Any TypeOrAttr = Union["Type", "TypeAttribute"] XEN_SIDNAMES: Any def lookup_boolean_name_sub(name: str) -> str: ... class AVRule(BaseTERule): default: NoReturn = ... perms: Set[str] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def derive_expanded(self, *args, **kwargs) -> AVRule: ... def expand(self, *args, **kwargs) -> Iterable[AVRule]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class AVRuleXperm(BaseTERule): default: NoReturn = ... perms: IoctlSet = ... xperm_type: str = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self, *args, **kwargs) -> Iterable[AVRuleXperm]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BaseConstraint(PolicyObject): expression: ConstraintExpression = ... perms: FrozenSet[str] = ... ruletype: ConstraintRuletype = ... tclass: ObjClass = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BaseMLSLevel(PolicyObject): sensitivity: Sensitivity = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def categories(self) -> Iterable[Category]: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BaseTERule(PolicyRule): conditional: Conditional = ... conditional_block: bool = ... filename: str = ... ruletype: TERuletype = ... source: TypeOrAttr = ... tclass: ObjClass = ... target: TypeOrAttr = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def enabled(self, **kwargs) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BaseType(PolicySymbol): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def aliases(self) -> Iterable[str]: ... def attributes(self) -> Iterable[BaseType]: ... def expand(self) -> Iterable[BaseType]: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Boolean(PolicySymbol): state: bool = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BooleanHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Boolean: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Bounds(PolicyObject): child: Type = ... parent: Type = ... ruletype: BoundsRuletype = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class BoundsRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... typebounds: int = ... class Category(PolicySymbol): _value: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def aliases(self, *args, **kwargs) -> Iterable[str]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class CategoryEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Category: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class CategoryHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Category: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Common(PolicySymbol): perms: FrozenSet[str] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __contains__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class CommonHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Common: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Conditional(PolicyObject): booleans: FrozenSet[Boolean] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def evaluate(self, **kwargs) -> bool: ... def expression(self) -> Iterable[Union[ConditionalOperator, str]]: ... def false_rules(self, *args, **kwargs) -> Iterable[AnyTERule]: ... def statement(self) -> str: ... def true_rules(self, *args, **kwargs) -> Iterable[AnyTERule]: ... def truth_table(self) -> List[TruthTableRow]: ... def __contains__(self, other) -> bool: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConditionalExprIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Union[ConditionalOperator, Boolean]: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConditionalIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Conditional: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConditionalOperator(PolicyObject): _cond_expr_val_to_details: Any = ... evaluate: Callable = ... precedence: int = ... unary: bool = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self, *args, **kwargs) -> NoReturn: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConditionalTERuleIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def ruletype_count(self, *args, **kwargs) -> Any: ... def __len__(self) -> int: ... def __next__(self) -> AnyTERule: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Constraint(BaseConstraint): perms: FrozenSet[str] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConstraintExprIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> ConstraintExprNode: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConstraintExprNode(PolicyObject): _expr_op_to_text: Any = ... _expr_type_to_text: Any = ... _role_syms: Any = ... _sym_to_text: Any = ... _type_syms: Any = ... _user_syms: Any = ... names: Union[FrozenSet[TypeOrAttr], FrozenSet[Role], FrozenSet[User]] = ... symbol_type: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> NoReturn: ... def __contains__(self, other) -> bool: ... def __getitem__(self, index) -> Union[str, FrozenSet[TypeOrAttr], FrozenSet[Role], FrozenSet[User]]: ... def __iter__(self) -> Iterable[Union[str, FrozenSet[TypeOrAttr], FrozenSet[Role], FrozenSet[User]]]: ... def __len__(self) -> int: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConstraintExpression(PolicyObject): mls: bool = ... roles: FrozenSet[Role] = ... types: FrozenSet[Type] = ... users: FrozenSet[User] = ... __hash__: Any = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def infix(self, *args, **kwargs) -> Union[str, FrozenSet[TypeOrAttr], FrozenSet[Role], FrozenSet[User]]: ... def statement(self) -> NoReturn: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __getitem__(self, index) -> Union[str, FrozenSet[TypeOrAttr], FrozenSet[Role], FrozenSet[User]]: ... def __gt__(self, other) -> bool: ... def __iter__(self) -> Iterator[Union[FrozenSet[Role], FrozenSet[Type], FrozenSet[User], str]]: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConstraintIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Constraint: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ConstraintRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... constrain: int = ... mlsconstrain: int = ... mlsvalidatetrans: int = ... validatetrans: int = ... class ConstraintUseError(setools.exception.SymbolUseError): ... class Context(PolicyObject): range_: Range = ... role: Role = ... type_: Type = ... user: User = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Default(PolicyObject): default: DefaultValue = ... ruletype: DefaultRuletype = ... tclass: ObjClass = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class DefaultRange(Default): default_range: DefaultRangeValue = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class DefaultRangeValue(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... high: int = ... low: int = ... low_high: int = ... @classmethod def from_default_range(self, range: Optional[int]) -> Optional[DefaultRangeValue]: ... class DefaultRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... default_range: int = ... default_role: int = ... default_type: int = ... default_user: int = ... class DefaultValue(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... glblub: int = ... source: int = ... target: int = ... @classmethod def from_default_range(self, *args, **kwargs) -> Any: ... class Devicetreecon(Ocontext): path: str = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class DevicetreeconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Devicetreecon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class EbitmapIterator(PolicyIterator): @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> PolicyObject: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class FSUse(Ocontext): fs: str = ... ruletype: FSUseRuletype = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class FSUseIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> FSUse: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class FSUseRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... fs_use_task: int = ... fs_use_trans: int = ... fs_use_xattr: int = ... class FileNameTERule(BaseTERule): default: Type = ... filename: str = ... perms: NoReturn = ... ruletype: TERuletype = ... source: TypeOrAttr = ... tclass: ObjClass = ... target: TypeOrAttr = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self, *args, **kwargs) -> Iterable[FileNameTERule]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class FileNameTERuleIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> FileNameTERule: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class GenfsFiletype(int): _filetype_to_text: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Genfscon(Ocontext): _sclass_to_stat: Any = ... filetype: GenfsFiletype = ... fs: str = ... path: str = ... tclass: ObjClass = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class GenfsconIterator: __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __iter__(self) -> Iterable[Genfscon]: ... def __len__(self) -> int: ... def __next__(self) -> Genfscon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class GenfsconOcontextIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Ocontext: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class HandleUnknown(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... allow: int = ... deny: int = ... reject: int = ... class HashtabIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Any: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Ibendportcon(Ocontext): name: str = ... port: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IbendportconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Ibendportcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Ibpkeycon(Ocontext): pkeys: IbpkeyconRange = ... subnet_prefix: ipaddress.IPv6Address = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IbpkeyconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Ibpkeycon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IbpkeyconRange(Tuple[int, int]): _asdict: Any = ... _field_defaults: Any = ... _fields: Any = ... _fields_defaults: Any = ... _replace: Any = ... high: int = ... low: int = ... __getnewargs__: Any = ... __slots__: Any = ... def __init__(self, *args, **kwargs) -> None: ... @classmethod def _make(self, *args, **kwargs) -> Any: ... class InitialSID(Ocontext): name: str = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class InitialSIDIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> InitialSID: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class InvalidBoolean(setools.exception.InvalidSymbol): ... class InvalidBoundsType(setools.exception.InvalidSymbol): ... class InvalidCategory(setools.exception.InvalidSymbol): ... class InvalidClass(setools.exception.InvalidSymbol): ... class InvalidCommon(setools.exception.InvalidSymbol): ... class InvalidConstraintType(setools.exception.InvalidSymbol): ... class InvalidDefaultRange(setools.exception.InvalidSymbol): ... class InvalidDefaultType(setools.exception.InvalidRuleType): ... class InvalidDefaultValue(setools.exception.InvalidSymbol): ... class InvalidFSUseType(setools.exception.InvalidRuleType): ... class InvalidInitialSid(setools.exception.InvalidSymbol): ... class InvalidLevel(setools.exception.InvalidSymbol): ... class InvalidLevelDecl(setools.exception.InvalidSymbol): ... class InvalidMLSRuleType(setools.exception.InvalidRuleType): ... class InvalidPolicy(ValueError, setools.exception.PolicyrepException): ... class InvalidRBACRuleType(setools.exception.InvalidRuleType): ... class InvalidRange(setools.exception.InvalidSymbol): ... class InvalidRole(setools.exception.InvalidSymbol): ... class InvalidRuleType(setools.exception.InvalidSymbol): ... class InvalidSensitivity(setools.exception.InvalidSymbol): ... class InvalidTERuleType(setools.exception.InvalidRuleType): ... class InvalidType(setools.exception.InvalidSymbol): ... class InvalidUser(setools.exception.InvalidSymbol): ... class IoctlSet(FrozenSet[int]): @classmethod def __init__(self, *args, **kwargs) -> None: ... def ranges(self) -> int: ... def __format__(self, *args, **kwargs) -> str: ... def __reduce_cython__(self, *args, **kwargs) -> Any: ... def __setstate_cython__(self, *args, **kwargs) -> Any: ... class Iomemcon(Ocontext): addr: IomemconRange = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IomemconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Iomemcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IomemconRange(Tuple[int, int]): _asdict: Any = ... _field_defaults: Any = ... _fields: Any = ... _fields_defaults: Any = ... _replace: Any = ... high: int = ... low: int = ... __getnewargs__: Any = ... __slots__: Any = ... def __init__(self, *args, **kwargs) -> None: ... @classmethod def _make(self, *args, **kwargs) -> Any: ... class Ioportcon(Ocontext): ports: IoportconRange = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IoportconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Ioportcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class IoportconRange(Tuple[int, int]): _asdict: Any = ... _field_defaults: Any = ... _fields: Any = ... _fields_defaults: Any = ... _replace: Any = ... high: int = ... low: int = ... __getnewargs__: Any = ... __slots__: Any = ... def __init__(self, *args, **kwargs) -> None: ... @classmethod def _make(self, *args, **kwargs) -> Any: ... class Level(BaseMLSLevel): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> NoReturn: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __rxor__(self, other) -> bool: ... def __setstate__(self, state) -> Any: ... def __xor__(self, other) -> bool: ... class LevelDecl(BaseMLSLevel): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class LevelDeclHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> LevelDecl: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class LowLevelPolicyError(ValueError, setools.exception.PolicyrepException): ... class MLSDisabled(setools.exception.PolicyrepException): ... class MLSRule(PolicyRule): default: Range = ... origin: MLSRule = ... ruletype: MLSRuletype = ... source: TypeOrAttr = ... tclass: ObjClass = ... target: TypeOrAttr = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self) -> Iterable[MLSRule]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class MLSRuleIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> MLSRuletype: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class MLSRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... range_transition: int = ... class Netifcon(Ocontext): netif: str = ... packet: Context = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class NetifconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Netifcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class NoCommon(AttributeError, setools.exception.PolicyrepException): ... class NoDefaults(setools.exception.InvalidSymbol): ... class NoStatement(setools.exception.SymbolUseError): ... class Nodecon(Ocontext): ip_version: NodeconIPVersion = ... network: Union[ipaddress.IPv4Network, ipaddress.IPv6Network] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class NodeconIPVersion(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... ipv4: int = ... ipv6: int = ... class NodeconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Nodecon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ObjClass(PolicySymbol): common: Common = ... perms: FrozenSet[str] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def constraints(self, *args, **kwargs) -> Iterable[Constraint]: ... def defaults(self, *args, **kwargs) -> Iterable[AnyDefault]: ... def statement(self) -> str: ... def validatetrans(self, *args, **kwargs) -> Iterable[Validatetrans]: ... def __contains__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ObjClassHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> ObjClass: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Ocontext(PolicyObject): context: Context = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class OcontextIterator(PolicyIterator): @classmethod def __init__(self, *args, **kwargs) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Ocontext: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Pcidevicecon(Ocontext): device: str = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PcideviceconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Pcidevicecon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PermissionVectorIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Pirqcon(Ocontext): irq: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PirqconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Pirqcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyCapability(PolicySymbol): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyCapabilityIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> PolicyCapability: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyEnum(enum.Enum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... @classmethod def lookup(self, value) -> Any: ... def __eq__(self, other) -> bool: ... def __format__(self, *args, **kwargs) -> Any: ... def __hash__(self) -> int: ... class PolicyIterator: @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __iter__(self) -> Any: ... def __len__(self) -> int: ... def __next__(self) -> Any: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyObject: policy: SELinuxPolicy = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __copy__(self) -> PolicyObject: ... def __deepcopy__(self) -> PolicyObject: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyRule(PolicyObject): conditional: Conditional = ... conditional_block: bool = ... extended: bool = ... origin: PolicyRule = ... ruletype: Any = ... source: PolicySymbol = ... target: PolicySymbol = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def enabled(self, **kwargs) -> bool: ... def expand(self) -> Any: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicySymbol(PolicyObject): name: str = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PolicyTarget(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... selinux: int = ... xen: int = ... class Portcon(Ocontext): ports: PortconRange = ... protocol: PortconProtocol = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PortconIterator(OcontextIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Portcon: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class PortconProtocol(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... dccp: int = ... sctp: int = ... tcp: int = ... udp: int = ... class PortconRange(Tuple[int, int]): _asdict: Any = ... _field_defaults: Any = ... _fields: Any = ... _fields_defaults: Any = ... _replace: Any = ... high: int = ... low: int = ... __getnewargs__: Any = ... __slots__: Any = ... def __init__(self, *args, **kwargs) -> None: ... @classmethod def _make(self, *args, **kwargs) -> Any: ... class RBACRuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... allow: int = ... role_transition: int = ... class Range(PolicyObject): high: Level = ... low: Level = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __contains__(self, other) -> bool: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Role(PolicySymbol): dominated_roles: FrozenSet[Role] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self) -> Iterable[Role]: ... def statement(self) -> str: ... def types(self) -> Iterable[Type]: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleAllow(PolicyRule): default: NoReturn = ... ruletype: RBACRuletype = ... source: Role = ... tclass: NoReturn = ... target: Role = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self) -> Iterable[RoleAllow]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleAllowIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> RoleAllow: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Any: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Role: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleTransition(PolicyRule): default: Role = ... ruletype: RBACRuletype = ... source: Role = ... tclass: ObjClass = ... target: TypeOrAttr = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self) -> Iterable[RoleTransition]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RoleTransitionIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> RoleTransition: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class RuleNotConditional(AttributeError, setools.exception.PolicyrepException): ... class RuleUseError(setools.exception.SymbolUseError): ... class SELinuxPolicy: allow_count: int = ... allowxperm_count: int = ... auditallow_count: int = ... auditallowxperm_count: int = ... boolean_count: int = ... category_count: int = ... class_count: int = ... common_count: int = ... conditional_count: int = ... constraint_count: int = ... default_count: int = ... devicetreecon_count: int = ... dontaudit_count: int = ... dontauditxperm_count: int = ... fs_use_count: int = ... genfscon_count: int = ... handle_unknown: HandleUnknown = ... ibendportcon_count: int = ... ibpkeycon_count: int = ... initialsids_count: int = ... iomemcon_count: int = ... ioportcon_count: int = ... level_count: int = ... mls: bool = ... mlsconstraint_count: int = ... mlsvalidatetrans_count: int = ... netifcon_count: int = ... neverallow_count: int = ... neverallowxperm_count: int = ... nodecon_count: int = ... path: str = ... pcidevicecon_count: int = ... permission_count: int = ... permissives_count: int = ... pirqcon_count: int = ... polcap_count: int = ... portcon_count: int = ... range_transition_count: int = ... role_allow_count: int = ... role_count: int = ... role_transition_count: int = ... target_platform: PolicyTarget = ... type_attribute_count: int = ... type_change_count: int = ... type_count: int = ... type_member_count: int = ... type_transition_count: int = ... typebounds_count: int = ... user_count: int = ... validatetrans_count: int = ... version: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, policyfile: Optional[str] = None) -> None: ... def bools(self) -> Iterable[Boolean]: ... def bounds(self) -> Iterable[Bounds]: ... def categories(self) -> Iterable[Category]: ... def classes(self) -> Iterable[ObjClass]: ... def commons(self) -> Iterable[Common]: ... def conditionals(self) -> Iterable[Conditional]: ... def constraints(regularandMLS) -> Iterable[AnyConstraint]: ... def defaults(self) -> Iterable[AnyDefault]: ... def devicetreecons(self) -> Iterable[Devicetreecon]: ... def fs_uses(self) -> Iterable[FSUse]: ... def genfscons(self) -> Iterable[Genfscon]: ... def ibendportcons(self) -> Iterable[Ibendportcon]: ... def ibpkeycons(self) -> Iterable[Ibpkeycon]: ... def initialsids(self) -> Iterable[InitialSID]: ... def iomemcons(self) -> Iterable[Iomemcon]: ... def ioportcons(self) -> Iterable[Ioportcon]: ... def levels(self) -> Iterable[Level]: ... def lookup_boolean(self, name: Union[Boolean, str]) -> Boolean: ... def lookup_category(self, name: Union[Category, str], deref: bool = True) -> Category: ... def lookup_class(self, name: Union[ObjClass, str]) -> ObjClass: ... def lookup_common(self, name: Union[Common, str]) -> Common: ... def lookup_initialsid(self, name: Union[InitialSID, str]) -> InitialSID: ... def lookup_level(self, name: Union[Level, str]) -> Level: ... def lookup_range(self, name: Union[Range, str]) -> Range: ... def lookup_role(self, name: Union[Role, str]) -> Role: ... def lookup_sensitivity(self, name: Union[Sensitivity, str]) -> Sensitivity: ... def lookup_type(self, name: Union[Type, str], deref: bool = True) -> Type: ... def lookup_type_or_attr(self, name: Union[TypeOrAttr, str], deref: bool = True) -> TypeOrAttr: ... def lookup_typeattr(self, name: Union[TypeAttribute, str]) -> TypeAttribute: ... def lookup_user(self, name: Union[User, str]) -> User: ... def mlsrules(self) -> Iterable[MLSRule]: ... def netifcons(self) -> Iterable[Netifcon]: ... def nodecons(self) -> Iterable[Nodecon]: ... def pcidevicecons(self) -> Iterable[Pcidevicecon]: ... def pirqcons(self) -> Iterable[Pirqcon]: ... def polcaps(self) -> Iterable[PolicyCapability]: ... def portcons(self) -> Iterable[Portcon]: ... def rbacrules(self) -> Iterable[AnyRBACRule]: ... def roles(self) -> Iterable[Role]: ... def sensitivities(self) -> Iterable[Sensitivity]: ... def terules(self) -> Iterable[AnyTERule]: ... def typeattributes(self) -> Iterable[TypeAttribute]: ... def types(self) -> Iterable[Type]: ... def users(self) -> Iterable[User]: ... def __copy__(self) -> SELinuxPolicy: ... def __deepcopy__(self) -> SELinuxPolicy: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Sensitivity(PolicySymbol): _value: int = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def aliases(self, *args, **kwargs) -> Any: ... def level_decl(self, *args, **kwargs) -> Any: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class SensitivityHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Sensitivity: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class SymbolUseError(AttributeError, setools.exception.PolicyrepException): ... class TERule(BaseTERule): default: Type = ... perms: NoReturn = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def expand(self) -> Iterable[TERule]: ... def statement(self) -> str: ... def __eq__(self, other) -> bool: ... def __ge__(self, other) -> bool: ... def __gt__(self, other) -> bool: ... def __hash__(self) -> int: ... def __le__(self, other) -> bool: ... def __lt__(self, other) -> bool: ... def __ne__(self, other) -> bool: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TERuleIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def ruletype_count(self, *args, **kwargs) -> Any: ... def __len__(self) -> int: ... def __next__(self) -> TERule: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TERuleNoFilename(AttributeError, setools.exception.PolicyrepException): ... class TERuletype(PolicyEnum): __new__: Any = ... _generate_next_value_: Any = ... _member_map_: Any = ... _member_names_: Any = ... _member_type_: Any = ... _value2member_map_: Any = ... allow: int = ... allowxperm: int = ... auditallow: int = ... auditallowxperm: int = ... dontaudit: int = ... dontauditxperm: int = ... neverallow: int = ... neverallowxperm: int = ... type_change: int = ... type_member: int = ... type_transition: int = ... class TruthTableRow(NamedTuple): values: Dict[str, bool] result: bool class Type(BaseType): ispermissive: bool = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def aliases(self) -> Iterable[str]: ... def attributes(self) -> Iterable[TypeAttribute]: ... def expand(self) -> Iterable[Type]: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeAttribute(BaseType): ispermissive: bool = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def aliases(self) -> Iterable[str]: ... def attributes(self) -> Iterable[TypeAttribute]: ... def expand(self) -> Iterable[Type]: ... def statement(self) -> str: ... def __contains__(self, other) -> bool: ... def __iter__(self) -> Iterable[TypeAttribute]: ... def __len__(self) -> int: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeAttributeEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> TypeAttribute: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeAttributeHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> TypeAttribute: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> Type: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Type: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeOrAttributeEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> TypeOrAttr: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class TypeboundsIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Bounds: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class User(PolicySymbol): mls_level: Level = ... mls_range: Range = ... roles: FrozenSet[Role] = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class UserEbitmapIterator(EbitmapIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> User: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class UserHashtabIterator(HashtabIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def __next__(self) -> User: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class Validatetrans(BaseConstraint): perms: NoReturn = ... __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def statement(self) -> str: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class ValidatetransIterator(PolicyIterator): __pyx_vtable__: Any = ... @classmethod def __init__(self, *args, **kwargs) -> None: ... def reset(self) -> None: ... def __len__(self) -> int: ... def __next__(self) -> Validatetrans: ... def __reduce__(self) -> Any: ... def __setstate__(self, state) -> Any: ... class WeakKeyDefaultDict(weakref.WeakKeyDictionary): _abc_impl: Any = ... __abstractmethods__: Any = ... def __init__(self, *args, **kwargs) -> None: ... def __getitem__(self, index) -> Any: ... def __missing__(self, *args, **kwargs) -> Any: ... setools-4.4.0/setools/policyrep.pyx000066400000000000000000000062511402045477700174650ustar00rootroot00000000000000# Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from cpython.exc cimport PyErr_SetFromErrnoWithFilename from cpython.mem cimport PyMem_Malloc, PyMem_Free from libc.errno cimport errno, EPERM, ENOENT, ENOMEM, EINVAL from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t from libc.stdio cimport FILE, fopen, fclose, snprintf from libc.stdlib cimport calloc, free from libc.string cimport memcpy, memset, strerror from posix.stat cimport S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFREG, S_IFLNK, S_IFSOCK import logging import warnings import itertools import ipaddress import collections import enum import weakref from typing import TypeVar, Union cimport sepol cimport selinux from .exception import InvalidPolicy, MLSDisabled, InvalidBoolean, InvalidCategory, InvalidClass, \ InvalidCommon, InvalidInitialSid, InvalidLevel, InvalidLevelDecl, InvalidRange, InvalidRole, \ InvalidSensitivity, InvalidType, InvalidUser, InvalidRuleType, InvalidBoundsType, \ InvalidConstraintType, InvalidDefaultType, InvalidFSUseType, InvalidMLSRuleType, \ InvalidRBACRuleType, InvalidTERuleType, SymbolUseError, RuleUseError, ConstraintUseError, \ NoStatement, InvalidDefaultValue, InvalidDefaultRange, NoCommon, NoDefaults, \ RuleNotConditional, TERuleNoFilename, LowLevelPolicyError cdef extern from "": int vasprintf(char **strp, const char *fmt, va_list ap) cdef extern from "": ctypedef struct va_list: pass void va_start(va_list, void* arg) void va_end(va_list) cdef extern from "": ctypedef unsigned int socklen_t cdef int AF_INET cdef int AF_INET6 cdef extern from "": cdef int INET6_ADDRSTRLEN cdef int IPPROTO_DCCP cdef int IPPROTO_SCTP cdef int IPPROTO_TCP cdef int IPPROTO_UDP cdef extern from "": cdef const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) # this must be here so that the PolicyEnum subclasses are created correctly. # otherwise you get an error during runtime include "util.pxi" include "boolcond.pxi" include "bounds.pxi" include "constraint.pxi" include "context.pxi" include "default.pxi" include "fscontext.pxi" include "initsid.pxi" include "mls.pxi" include "mlsrule.pxi" include "netcontext.pxi" include "objclass.pxi" include "object.pxi" include "polcap.pxi" include "rbacrule.pxi" include "role.pxi" include "rule.pxi" include "selinuxpolicy.pxi" include "terule.pxi" include "typeattr.pxi" include "user.pxi" include "xencontext.pxi" setools-4.4.0/setools/policyrep/000077500000000000000000000000001402045477700167175ustar00rootroot00000000000000setools-4.4.0/setools/policyrep/boolcond.pxi000066400000000000000000000265741402045477700212560ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2017-2018 Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # TruthTableRow = collections.namedtuple("TruthTableRow", ["values", "result"]) cdef object _cond_cache = WeakKeyDefaultDict(dict) # # Classes # cdef class Boolean(PolicySymbol): """A Boolean.""" cdef readonly bint state @staticmethod cdef inline Boolean factory(SELinuxPolicy policy, sepol.cond_bool_datum_t *symbol): """Factory function for creating Boolean objects.""" cdef Boolean b = Boolean.__new__(Boolean) b.policy = policy b.key = symbol b.name = policy.boolean_value_to_name(symbol.s.value - 1) b.state = symbol.state return b def statement(self): """The policy statement.""" return "bool {0} {1};".format(self.name, str(self.state).lower()) cdef class Conditional(PolicyObject): """A conditional policy block.""" cdef: list _postfix_expression readonly frozenset booleans @staticmethod cdef inline Conditional factory(SELinuxPolicy policy, sepol.cond_node_t *symbol): """Factory function for creating Conditional objects.""" cdef: Conditional c list booleans try: return _cond_cache[policy][symbol] except KeyError: c = Conditional.__new__(Conditional) _cond_cache[policy][symbol] = c c.policy = policy c.key = symbol c._postfix_expression = [] booleans = [] # Build expression list and boolean attribute for n in ConditionalExprIterator.factory(policy, symbol.expr): c._postfix_expression.append(n) if isinstance(n, Boolean): booleans.append(n) c.booleans = frozenset(booleans) return c def __contains__(self, other): return other in self.booleans def __str__(self): # sepol representation is in postfix notation. This code # converts it to infix notation. Parentheses are added # to ensure correct expressions, though they may end up # being overused. Set previous operator at start to the # highest precedence (NOT) so if there is a single binary # operator, no parentheses are output stack = [] prev_op_precedence = 5 for expr_node in self.expression(): if isinstance(expr_node, Boolean): # append the boolean name stack.append(str(expr_node)) elif expr_node.unary: operand = stack.pop() operator = str(expr_node) op_precedence = expr_node.precedence # NOT is the highest precedence, so only need # parentheses if the operand is a subexpression if isinstance(operand, list): subexpr = [operator, "(", operand, ")"] else: subexpr = [operator, operand] stack.append(subexpr) prev_op_precedence = op_precedence else: operand1 = stack.pop() operand2 = stack.pop() operator = str(expr_node) op_precedence = expr_node.precedence if prev_op_precedence > op_precedence: # if previous operator is of higher precedence # no parentheses are needed. subexpr = [operand1, operator, operand2] else: subexpr = ["(", operand1, operator, operand2, ")"] stack.append(subexpr) prev_op_precedence = op_precedence return ' '.join(flatten_list(stack)) def __hash__(self): return hash(self.key) def __eq__(self, other): try: return self._eq(other) except TypeError: return str(self) == str(other) def evaluate(self, **kwargs): """ Evaluate the expression with the stated boolean values. Keyword Parameters: bool_name=True|False Each keyword parameter name corresponds to a Boolean name in the expression and the state to use in the evaluation. If a Boolean value is not set, its default value is used. Extra values are ignored. Return: bool """ cdef: list stack = [] dict bool_values = {b.name: kwargs.get(b.name, b.state) for b in self.booleans} ConditionalOperator operator for expr_node in self.expression(): if isinstance(expr_node, Boolean): stack.append(bool_values[expr_node]) elif expr_node.unary: operand = stack.pop() operator = expr_node stack.append(operator.evaluate(operand)) else: operand1 = stack.pop() operand2 = stack.pop() operator = expr_node stack.append(operator.evaluate(operand1, operand2)) return stack[0] def expression(self): """Iterator over The conditional expression.""" return iter(self._postfix_expression) def false_rules(self): """An iterator over the rules in the false (else) block of the conditional.""" cdef sepol.cond_node_t *symbol = self.key return ConditionalTERuleIterator.factory(self.policy, symbol.false_list, self, False) def statement(self): raise NoStatement def true_rules(self): """An iterator over the rules in the true block of the conditional.""" cdef sepol.cond_node_t *symbol = self.key return ConditionalTERuleIterator.factory(self.policy, symbol.true_list, self, True) def truth_table(self): """ Generate a truth table for this expression. Return: list List item: tuple: values, result Tuple item: values: Dictionary keyed on Boolean names with each value being T/F. result: Evaluation result for the expression given the values. Example return for "a || b" [({"a": True, "b": True}, True), ({"a": True, "b": False}, True), ({"a": False, "b": True}, True), ({"a": False, "b": False}, False)] """ bools = sorted(str(b) for b in self.booleans) truth_table = [] # create a list of all combinations of T/F for each Boolean truth_list = list(itertools.product([True, False], repeat=len(bools))) for row in truth_list: values = {bools[i]: row[i] for i in range(len(bools))} truth_table.append(TruthTableRow(values, self.evaluate(**values))) return truth_table cdef class ConditionalOperator(PolicyObject): """A conditional expression operator""" cdef: str text readonly int precedence # T/F the operator is unary readonly bint unary # stores a callable for evaluating # using the specified operands. # see _cond_expr_val_to_eval readonly object evaluate _cond_expr_val_to_details = { sepol.COND_NOT: ("!", 5, lambda x: not x), sepol.COND_OR: ("||", 1, lambda x, y: x or y), sepol.COND_AND: ("&&", 3, lambda x, y: x and y), sepol.COND_XOR: ("^", 2, lambda x, y: x ^ y), sepol.COND_EQ: ("==", 4, lambda x, y: x == y), sepol.COND_NEQ: ("!=", 4, lambda x, y: x != y)} @staticmethod cdef inline ConditionalOperator factory(SELinuxPolicy policy, sepol.cond_expr_t *symbol): """Factory function for conditional operators.""" cdef ConditionalOperator op = ConditionalOperator.__new__(ConditionalOperator) op.policy = policy op.key = symbol op.unary = symbol.expr_type == sepol.COND_NOT op.text, op.precedence, op.evaluate = op._cond_expr_val_to_details[symbol.expr_type] return op def __str__(self): return self.text def statement(self): raise NoStatement # # Iterators # cdef class BooleanHashtabIterator(HashtabIterator): """Iterate over Booleans in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Boolean iterators.""" i = BooleanHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return Boolean.factory(self.policy, self.curr.datum) cdef class ConditionalIterator(PolicyIterator): """Conditionals iterator.""" cdef: sepol.cond_node_t *head sepol.cond_node_t *curr @staticmethod cdef factory(SELinuxPolicy policy, sepol.cond_node_t *head): """Constraint iterator factory.""" c = ConditionalIterator() c.policy = policy c.head = head c.reset() return c def __next__(self): if self.curr == NULL: raise StopIteration item = Conditional.factory(self.policy, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.cond_node_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head cdef class ConditionalExprIterator(PolicyIterator): """Conditional expression iterator.""" cdef: sepol.cond_expr_t *head sepol.cond_expr_t *curr @staticmethod cdef factory(SELinuxPolicy policy, sepol.cond_expr_t *head): """Conditional expression iterator factory.""" e = ConditionalExprIterator() e.policy = policy e.head = head e.reset() return e def __next__(self): if self.curr == NULL: raise StopIteration if self.curr.expr_type == sepol.COND_BOOL: item = Boolean.factory(self.policy, self.policy.boolean_value_to_datum(self.curr.bool - 1)) else: item = ConditionalOperator.factory(self.policy, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.cond_expr_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head setools-4.4.0/setools/policyrep/bounds.pxi000066400000000000000000000072241402045477700207400ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Classes # class BoundsRuletype(PolicyEnum): """Enumeration of *bounds rule types.""" typebounds = 1 cdef class Bounds(PolicyObject): """A bounds statement.""" cdef: readonly object ruletype readonly object parent readonly object child @staticmethod cdef inline Bounds factory(SELinuxPolicy policy, parent, child): """Factory function for creating Bounds objects.""" cdef Bounds b = Bounds.__new__(Bounds) b.policy = policy b.ruletype = BoundsRuletype.typebounds b.parent = parent b.child = child return b def __hash__(self): return hash("{0.ruletype}|{0.child};".format(self)) def __eq__(self, other): return self.policy == other.policy \ and self.ruletype == other.ruletype \ and self.parent == other.parent \ and self.child == other.child def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "{0.ruletype} {0.parent} {0.child};".format(self) # # Iterators # cdef class TypeboundsIterator(HashtabIterator): """Iterate over typebounds rules in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating typebounds iterators.""" i = TypeboundsIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): cdef sepol.type_datum_t *datum super().__next__() datum = self.curr.datum while datum.flavor != sepol.TYPE_TYPE or datum.bounds == 0: super().__next__() datum = self.curr.datum return Bounds.factory(self.policy, Type.factory(self.policy, self.policy.type_value_to_datum(datum.bounds - 1)), Type.factory(self.policy, datum)) def __len__(self): cdef: sepol.type_datum_t *datum sepol.hashtab_node_t *node uint32_t bucket = 0 size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and datum.flavor == sepol.TYPE_TYPE and datum.bounds != 0: count += 1 node = node.next bucket += 1 return count def reset(self): cdef sepol.type_datum_t * datum super().reset() # advance over any attributes or aliases datum = self.node.datum while datum != NULL and datum.flavor != sepol.TYPE_TYPE and datum.bounds == 0: self._next_node() datum = self.node.datum setools-4.4.0/setools/policyrep/constraint.pxi000066400000000000000000000377241402045477700216420ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Typing # AnyConstraint = TypeVar("AnyConstraint", bound=BaseConstraint) # # Classes # class ConstraintRuletype(PolicyEnum): """Enumeration of constraint types.""" constrain = 1 mlsconstrain = 2 validatetrans = 3 mlsvalidatetrans = 4 cdef class BaseConstraint(PolicyObject): """Base class for constraint rules.""" cdef: readonly object ruletype readonly object tclass readonly ConstraintExpression expression @property def perms(self): raise NotImplementedError cdef class Constraint(BaseConstraint): """A constraint rule (constrain/mlsconstrain).""" cdef readonly frozenset perms @staticmethod cdef factory(SELinuxPolicy policy, ObjClass tclass, sepol.constraint_node_t *symbol): """Factory function for creating Constraint objects.""" cdef Constraint c = Constraint.__new__(Constraint) c.policy = policy c.key = symbol c.tclass = tclass c.perms = frozenset(PermissionVectorIterator.factory(policy, tclass, symbol.permissions)) c.expression = ConstraintExpression.factory(policy, symbol.expr) c.ruletype = ConstraintRuletype.mlsconstrain if c.expression.mls \ else ConstraintRuletype.constrain return c def statement(self): if len(self.perms) > 1: perms = "{{ {0} }}".format(' '.join(self.perms)) else: # convert to list since sets cannot be indexed perms = list(self.perms)[0] return "{0.ruletype} {0.tclass} {1} ({0.expression}); ".format(self, perms) cdef class Validatetrans(BaseConstraint): """A validatetrans rule (validatetrans/mlsvalidatetrans).""" @staticmethod cdef factory(SELinuxPolicy policy, ObjClass tclass, sepol.constraint_node_t *symbol): """Factory function for creating Validatetrans objects.""" cdef Validatetrans v = Validatetrans.__new__(Validatetrans) v.policy = policy v.key = symbol v.tclass = tclass v.expression = ConstraintExpression.factory(policy, symbol.expr) v.ruletype = ConstraintRuletype.mlsvalidatetrans if v.expression.mls else \ ConstraintRuletype.validatetrans return v @property def perms(self): raise ConstraintUseError("{0} rules do not have permissions.".format(self.ruletype)) def statement(self): return "{0.ruletype} {0.tclass} ({0.expression});".format(self) cdef class ConstraintExpression(PolicyObject): """ A a list-like object representing a constraint's expression. The expression is in postfix notation, as that is how it is stored in the policy. The string representation, however, is in infix notation, as that is how it is written by policy writers. """ cdef: list _infix list _postfix readonly bint mls readonly frozenset users readonly frozenset roles readonly frozenset types # There is no levels attribute as specific # levels cannot be used in expressions, only # the l1, h1, etc. symbols @staticmethod cdef inline ConstraintExpression factory(SELinuxPolicy policy, sepol.constraint_expr_t *symbol): """Factory function for creating ConstraintExpression objects.""" cdef: ConstraintExpression e = ConstraintExpression.__new__(ConstraintExpression) list users = [] list roles = [] list types = [] ConstraintExprNode expr_node e.policy = policy e._postfix = [] for expr_node in ConstraintExprIterator.factory(policy, symbol): if expr_node.mls: e.mls = 1 if expr_node.types: types.extend(expr_node.names) elif expr_node.roles: roles.extend(expr_node.names) elif expr_node.users: users.extend(expr_node.names) e._postfix.extend(expr_node) e.users = frozenset(users) e.roles = frozenset(roles) e.types = frozenset(types) return e def __str__(self): cdef list ret = [] for item in self.infix(): if isinstance(item, frozenset): if len(item) > 1: ret.append("{{ {0} }} ".format(" ".join(str(j) for j in item))) else: ret.append("{0}".format(" ".join(str(j) for j in item))) else: ret.append(item) return " ".join(ret) def __getitem__(self, idx): return self._postfix[idx] def __iter__(self): return iter(self._postfix) def __eq__(self, other): return self._postfix == other def infix(self): """The expression as an infix notation list.""" if self._infix is None: self._infix = [] _precedence = { "not": 4, "and": 2, "or": 1, "==": 3, "!=": 3, "dom": 3, "domby": 3, "incomp": 3} _max_precedence = 4 _operands = ["u1", "u2", "u3", "r1", "r2", "r3", "t1", "t2", "t3", "l1", "l2", "h1", "h2"] # sepol representation is in postfix notation. This code # converts it to infix notation. Parentheses are added # to ensure correct expressions, though they may end up # being overused. Set previous operator at start to the # highest precedence (op) so if there is a single binary # operator, no parentheses are output stack = [] prev_op_precedence = _max_precedence for op in self._postfix: if isinstance(op, frozenset) or op in _operands: # operands stack.append(op) else: # operators if op == "not": # unary operator operator = op operand = stack.pop() op_precedence = _precedence[op] stack.append([operator, "(", operand, ")"]) else: # binary operators operand2 = stack.pop() operand1 = stack.pop() operator = op # if previous operator is of higher precedence # no parentheses are needed. if _precedence[op] < prev_op_precedence: stack.append([operand1, operator, operand2]) else: stack.append(["(", operand1, operator, operand2, ")"]) prev_op_precedence = _precedence[op] self._infix = flatten_list(stack) return self._infix def statement(self): raise NoStatement cdef class ConstraintExprNode(PolicyObject): """ A node of the low-level constraint expression. This is an immutable list-like object that contains one node of a constraint in postfix notation, e.g.: ["u1", "u2", "=="] This is only used for initializing a ConstraintExpression object. """ cdef: uint32_t expression_type uint32_t operator uint32_t _symbol_type frozenset _names list _expression # T/F this node is MLS bint mls # T/F this node has roles/types/users bint roles bint types bint users _expr_type_to_text = { sepol.CEXPR_NOT: "not", sepol.CEXPR_AND: "and", sepol.CEXPR_OR: "or"} _expr_op_to_text = { sepol.CEXPR_EQ: "==", sepol.CEXPR_NEQ: "!=", sepol.CEXPR_DOM: "dom", sepol.CEXPR_DOMBY: "domby", sepol.CEXPR_INCOMP: "incomp"} _sym_to_text = { sepol.CEXPR_USER: "u1", sepol.CEXPR_ROLE: "r1", sepol.CEXPR_TYPE: "t1", sepol.CEXPR_USER + sepol.CEXPR_TARGET: "u2", sepol.CEXPR_ROLE + sepol.CEXPR_TARGET: "r2", sepol.CEXPR_TYPE + sepol.CEXPR_TARGET: "t2", sepol.CEXPR_USER + sepol.CEXPR_XTARGET: "u3", sepol.CEXPR_ROLE + sepol.CEXPR_XTARGET: "r3", sepol.CEXPR_TYPE + sepol.CEXPR_XTARGET: "t3", sepol.CEXPR_L1L2: "l1", sepol.CEXPR_L1H2: "l1", sepol.CEXPR_H1L2: "h1", sepol.CEXPR_H1H2: "h1", sepol.CEXPR_L1H1: "l1", sepol.CEXPR_L2H2: "l2", sepol.CEXPR_L1L2 + sepol.CEXPR_TARGET: "l2", sepol.CEXPR_L1H2 + sepol.CEXPR_TARGET: "h2", sepol.CEXPR_H1L2 + sepol.CEXPR_TARGET: "l2", sepol.CEXPR_H1H2 + sepol.CEXPR_TARGET: "h2", sepol.CEXPR_L1H1 + sepol.CEXPR_TARGET: "h1", sepol.CEXPR_L2H2 + sepol.CEXPR_TARGET: "h2"} _role_syms = [sepol.CEXPR_ROLE, sepol.CEXPR_ROLE + sepol.CEXPR_TARGET, sepol.CEXPR_ROLE + sepol.CEXPR_XTARGET] _type_syms = [sepol.CEXPR_TYPE, sepol.CEXPR_TYPE + sepol.CEXPR_TARGET, sepol.CEXPR_TYPE + sepol.CEXPR_XTARGET] _user_syms = [sepol.CEXPR_USER, sepol.CEXPR_USER + sepol.CEXPR_TARGET, sepol.CEXPR_USER + sepol.CEXPR_XTARGET] @staticmethod cdef inline ConstraintExprNode factory(SELinuxPolicy policy, sepol.constraint_expr_t *symbol): """Factory function for creating ConstraintExprNode objects.""" cdef ConstraintExprNode n = ConstraintExprNode.__new__(ConstraintExprNode) n.policy = policy n.key = symbol n.expression_type = symbol.expr_type n.operator = symbol.op # # Determine attributes of expression node # if symbol.expr_type in (sepol.CEXPR_ATTR, sepol.CEXPR_NAMES): n._symbol_type = symbol.attr try: n.mls = n.symbol_type >= sepol.CEXPR_L1L2 if symbol.expr_type == sepol.CEXPR_NAMES: if n.symbol_type in n._role_syms: n.roles = True n._names = frozenset(r for r in RoleEbitmapIterator.factory(policy, &symbol.names)) elif n.symbol_type in n._type_syms: n.types = True if policy.version > 28: n._names = frozenset(t for t in TypeOrAttributeEbitmapIterator.factory_from_set( policy, symbol.type_names)) else: n._names = frozenset(t for t in TypeEbitmapIterator.factory( policy, &symbol.names)) else: n.users = True n._names = frozenset(u for u in UserEbitmapIterator.factory(policy, &symbol.names)) except AttributeError: pass # # Build expression # if n.expression_type == sepol.CEXPR_ATTR: # logical operator with symbols (e.g. u1 == u2) operand1 = n._sym_to_text[n.symbol_type] operand2 = n._sym_to_text[n.symbol_type + sepol.CEXPR_TARGET] operator = n._expr_op_to_text[n.operator] n._expression = [operand1, operand2, operator] elif n.expression_type == sepol.CEXPR_NAMES: # logical operator with type or attribute list (e.g. t1 == { spam_t eggs_t }) operand1 = n._sym_to_text[n.symbol_type] operand2 = n.names operator = n._expr_op_to_text[n.operator] n._expression = [operand1, operand2, operator] else: # individual operators (and/or/not) n._expression = [n._expr_type_to_text[n.expression_type]] return n def __iter__(self): return iter(self._expression) def __contains__(self, item): return item in self._expression def __len__(self): return len(self._expression) def __getitem__(self, idx): return self._expression[idx] @property def names(self): if self._names is None: raise AttributeError("names") return self._names @property def symbol_type(self): if self._symbol_type is None: raise AttributeError("symbol_type") return self._symbol_type def statement(self): raise NoStatement # # Iterators # cdef class ConstraintIterator(PolicyIterator): """Constraint iterator.""" cdef: sepol.constraint_node_t *head sepol.constraint_node_t *curr ObjClass tclass @staticmethod cdef factory(SELinuxPolicy policy, ObjClass tclass, sepol.constraint_node_t *head): """Constraint iterator factory.""" c = ConstraintIterator() c.policy = policy c.head = head c.tclass = tclass c.reset() return c def __next__(self): if self.curr == NULL: raise StopIteration item = Constraint.factory(self.policy, self.tclass, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.constraint_node_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head cdef class ValidatetransIterator(ConstraintIterator): """Validatetrans iterator.""" @staticmethod cdef factory(SELinuxPolicy policy, ObjClass tclass, sepol.constraint_node_t *head): """Validatetrans iterator factory.""" v = ValidatetransIterator() v.policy = policy v.head = head v.tclass = tclass v.reset() return v def __next__(self): if self.curr == NULL: raise StopIteration item = Validatetrans.factory(self.policy, self.tclass, self.curr) self.curr = self.curr.next return item cdef class ConstraintExprIterator(PolicyIterator): """ Constraint low-level expression iterator. This is only used for initializing a ConstraintExpression object. """ cdef: sepol.constraint_expr_t *head sepol.constraint_expr_t *curr @staticmethod cdef factory(SELinuxPolicy policy, sepol.constraint_expr_t *head): """Constraint expression iterator factory.""" e = ConstraintExprIterator() e.policy = policy e.head = head e.reset() return e def __next__(self): if self.curr == NULL: raise StopIteration item = ConstraintExprNode.factory(self.policy, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.constraint_expr_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head setools-4.4.0/setools/policyrep/context.pxi000066400000000000000000000040031402045477700211220ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef class Context(PolicyObject): """A SELinux security context/security attribute.""" cdef: readonly User user readonly Role role readonly Type type_ Range _range @staticmethod cdef inline Context factory(SELinuxPolicy policy, sepol.context_struct_t *symbol): """Factory function for creating Context objects.""" cdef Context c = Context.__new__(Context) c.policy = policy c.key = symbol c.user = User.factory(policy, policy.user_value_to_datum(symbol.user - 1)) c.role = Role.factory(policy, policy.role_value_to_datum(symbol.role - 1)) c.type_ = Type.factory(policy, policy.type_value_to_datum(symbol.type - 1)) if policy.mls: c._range = Range.factory(policy, &symbol.range) return c def __str__(self): if self._range: return "{0.user}:{0.role}:{0.type_}:{0.range_}".format(self) else: return "{0.user}:{0.role}:{0.type_}".format(self) @property def range_(self): """The MLS range of the context.""" if self._range: return self._range else: raise MLSDisabled def statement(self): raise NoStatement setools-4.4.0/setools/policyrep/default.pxi000066400000000000000000000132021402045477700210630ustar00rootroot00000000000000# Copyright 2014, 2016 Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Typing and enums # AnyDefault = Union[Default, DefaultRange] class DefaultRuletype(PolicyEnum): """Enumeration of default rule types.""" default_user = 1 default_role = 2 default_type = 3 default_range = 4 class DefaultValue(PolicyEnum): """Enumeration of default values.""" source = sepol.DEFAULT_SOURCE target = sepol.DEFAULT_TARGET glblub = sepol.DEFAULT_GLBLUB @classmethod def from_default_range(cls, range_): default_map = {sepol.DEFAULT_SOURCE_LOW: sepol.DEFAULT_SOURCE, sepol.DEFAULT_SOURCE_HIGH: sepol.DEFAULT_SOURCE, sepol.DEFAULT_SOURCE_LOW_HIGH: sepol.DEFAULT_SOURCE, sepol.DEFAULT_TARGET_LOW: sepol.DEFAULT_TARGET, sepol.DEFAULT_TARGET_HIGH: sepol.DEFAULT_TARGET, sepol.DEFAULT_TARGET_LOW_HIGH: sepol.DEFAULT_TARGET, sepol.DEFAULT_GLBLUB: sepol.DEFAULT_GLBLUB} try: return cls(default_map[range_]) except KeyError as e: raise LowLevelPolicyError("Unsupported default value: {}".format(e)) from e class DefaultRangeValue(PolicyEnum): """Enumeration of default range values.""" low = 1 high = 2 low_high = 3 @classmethod def from_default_range(cls, range_): default_map = {sepol.DEFAULT_SOURCE_LOW: 1, sepol.DEFAULT_SOURCE_HIGH: 2, sepol.DEFAULT_SOURCE_LOW_HIGH: 3, sepol.DEFAULT_TARGET_LOW: 1, sepol.DEFAULT_TARGET_HIGH: 2, sepol.DEFAULT_TARGET_LOW_HIGH: 3, sepol.DEFAULT_GLBLUB: None} try: value = default_map[range_] return None if value is None else cls(value) except KeyError as e: raise LowLevelPolicyError("Unsupported default_range value: {}".format(e)) from e # # Classes # cdef class Default(PolicyObject): """Base class for default_* statements.""" cdef: readonly object ruletype readonly ObjClass tclass object _default # the default object is not exposed as a Python # attribute, as it collides with CPython code @staticmethod cdef inline Default factory(SELinuxPolicy policy, ObjClass tclass, user, role, type_, range_): """Factory function for Default objects.""" cdef: Default obj DefaultRange objr if user: obj = Default() obj.policy = policy obj.tclass = tclass obj.ruletype = DefaultRuletype.default_user obj._default = DefaultValue(user) return obj if role: obj = Default() obj.policy = policy obj.tclass = tclass obj.ruletype = DefaultRuletype.default_role obj._default = DefaultValue(role) return obj if type_: obj = Default() obj.policy = policy obj.tclass = tclass obj.ruletype = DefaultRuletype.default_type obj._default = DefaultValue(type_) return obj if range_: objr = DefaultRange() objr.policy = policy objr.ruletype = DefaultRuletype.default_range objr.tclass = tclass objr._default = DefaultValue.from_default_range(range_) objr.default_range = DefaultRangeValue.from_default_range(range_) return objr raise ValueError("At least one of user, role, type_, or range_ must be specified.") def __eq__(self, other): return self.ruletype == other.ruletype \ and self.tclass == other.tclass \ and self.default == other.default def __hash__(self): return hash("{0.ruletype}|{0.tclass}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) @property def default(self): return self._default def statement(self): return "{0.ruletype} {0.tclass} {0.default};".format(self) cdef class DefaultRange(Default): """A default_range statement.""" cdef readonly object default_range def __eq__(self, other): return self.ruletype == other.ruletype \ and self.tclass == other.tclass \ and self.default == other.default \ and self.default_range == other.default_range def __hash__(self): return hash("{0.ruletype}|{0.tclass}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): if self.default_range: return "{0.ruletype} {0.tclass} {0.default} {0.default_range};".format(self) else: return "{0.ruletype} {0.tclass} {0.default};".format(self) setools-4.4.0/setools/policyrep/fscontext.pxi000066400000000000000000000156161402045477700214670ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016-2018, 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Classes # class FSUseRuletype(PolicyEnum): """Enumeration of fs_use_* rule types.""" # there are more rule types, but modern SELinux # only supports these three. fs_use_xattr = sepol.SECURITY_FS_USE_XATTR fs_use_trans = sepol.SECURITY_FS_USE_TRANS fs_use_task = sepol.SECURITY_FS_USE_TASK cdef class FSUse(Ocontext): """An fs_use_* statement.""" cdef: readonly object ruletype readonly str fs @staticmethod cdef inline FSUse factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating FSUse objects.""" cdef FSUse f = FSUse.__new__(FSUse) f.policy = policy f.ruletype = FSUseRuletype(symbol.v.behavior) f.fs = intern(symbol.u.name) f.context = Context.factory(policy, symbol.context) return f def __hash__(self): return hash("{0.ruletype}|{0.fs}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "{0.ruletype} {0.fs} {0.context};".format(self) cdef class GenfsFiletype(int): """ A genfscon file type. The possible values are equivalent to file type values in the stat module, e.g. S_IFBLK, but overrides the string representation with the corresponding genfscon file type string (-b, -c, etc.) If the genfscon has no specific file type, this is 0, (empty string). """ _filetype_to_text = {0: "", S_IFBLK: "-b", S_IFCHR: "-c", S_IFDIR: "-d", S_IFIFO: "-p", S_IFREG: "--", S_IFLNK: "-l", S_IFSOCK: "-s"} def __str__(self): return self._filetype_to_text[self] cdef class Genfscon(Ocontext): """A genfscon statement.""" cdef: readonly str fs readonly object filetype readonly ObjClass tclass readonly str path _sclass_to_stat = {0: 0, "dir": S_IFDIR, "file": S_IFREG, "lnk_file": S_IFLNK, "fifo_file": S_IFIFO, "sock_file": S_IFSOCK, "blk_file": S_IFBLK, "chr_file": S_IFCHR} @staticmethod cdef inline Genfscon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol, fstype): """Factory function for creating Genfscon objects.""" cdef Genfscon g = Genfscon.__new__(Genfscon) g.policy = policy g.key = symbol g.fs = fstype g.path = intern(symbol.u.name) if symbol.v.sclass: try: g.tclass = ObjClass.factory(policy, policy.class_value_to_datum(symbol.v.sclass-1)) g.filetype = GenfsFiletype(Genfscon._sclass_to_stat[g.tclass.name]) except KeyError as ex: log = logging.getLogger(__name__) log.warning("Genfscon {} {} object class {} does not match a file object class. " "Dropping file type.".format(g.fs, g.path, g.tclass.name)) g.filetype = GenfsFiletype(0) g.tclass = None else: g.filetype = GenfsFiletype(0) g.tclass = None g.context = Context.factory(policy, symbol.context) return g def __hash__(self): return hash("genfscon|{0.fs}|{0.path}|{0.filetype}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "genfscon {0.fs} {0.path} {0.filetype} {0.context}".format(self) # # Iterators # cdef class FSUseIterator(OcontextIterator): """Iterator for fs_use_* statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating FSUse iterators.""" i = FSUseIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return FSUse.factory(self.policy, self.ocon) cdef class GenfsconIterator: """Iterator for genfscon statements in the policy.""" cdef: sepol.genfs_t *head sepol.genfs_t *curr object ocon_iter SELinuxPolicy policy @staticmethod cdef factory(SELinuxPolicy policy, sepol.genfs_t *head): """Factory function for creating genfscon iterators.""" i = GenfsconIterator() i.policy = policy i.head = i.curr = head return i def __iter__(self): return self def __next__(self): # consume sub-iterator first, if one exists if self.ocon_iter: try: return self.ocon_iter.__next__() except StopIteration: # sub_iter completed, clear self.ocon_iter = None if self.curr == NULL: raise StopIteration # create a sub-iterator for this fs entry self.ocon_iter = GenfsconOcontextIterator.factory(self.policy, self.curr.head, intern(self.curr.fstype)) self.curr = self.curr.next return self.ocon_iter.__next__() def __len__(self): cdef: size_t count = 0 sepol.genfs_t *genfs = self.head while genfs: count += len(GenfsconOcontextIterator.factory(self.policy, genfs.head, genfs.fstype)) genfs = genfs.next return count cdef class GenfsconOcontextIterator(OcontextIterator): """Sub-iterator for genfscon statements.""" cdef str fs @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head, fstype): """Factory function for creating genfscon sub-iterators.""" i = GenfsconOcontextIterator() i.policy = policy i.head = i.curr = head i.fs = fstype return i def __next__(self): super().__next__() return Genfscon.factory(self.policy, self.ocon, self.fs) setools-4.4.0/setools/policyrep/initsid.pxi000066400000000000000000000053531402045477700211120ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Constants # # Binary policy does not contain the SID names SELINUX_SIDNAMES = ("undefined", "kernel", "security", "unlabeled", "fs", "file", "file_labels", "init", "any_socket", "port", "netif", "netmsg", "node", "igmp_packet", "icmp_socket", "tcp_socket", "sysctl_modprobe", "sysctl", "sysctl_fs", "sysctl_kernel", "sysctl_net", "sysctl_net_unix", "sysctl_vm", "sysctl_dev", "kmod", "policy", "scmp_packet", "devnull") XEN_SIDNAMES = ("xen", "dom0", "domxen", "domio", "unlabeled", "security", "irq", "iomem", "ioport", "device", "domU", "domDM") # # Classes # cdef class InitialSID(Ocontext): """An initial SID statement.""" cdef readonly str name @staticmethod cdef inline InitialSID factory(SELinuxPolicy policy, sepol.ocontext *symbol): """Factory function for creating InitialSID objects.""" cdef InitialSID i = InitialSID.__new__(InitialSID) i.policy = policy i.key = symbol i.context = Context.factory(policy, symbol.context) if symbol.u.name: i.name = intern(symbol.u.name) elif policy.target_platform == PolicyTarget.selinux: i.name = SELINUX_SIDNAMES[symbol.sid[0]] elif policy.target_platform == PolicyTarget.xen: i.name = XEN_SIDNAMES[symbol.sid[0]] else: raise NotImplementedError return i def __str__(self): return self.name def statement(self): return "sid {0} {0.context}".format(self) cdef class InitialSIDIterator(OcontextIterator): """Iterator for initial SID statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating initial SID iterators.""" i = InitialSIDIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return InitialSID.factory(self.policy, self.ocon) setools-4.4.0/setools/policyrep/mls.pxi000066400000000000000000000510261402045477700202400ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2017-2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=protected-access cdef object _cat_cache = WeakKeyDefaultDict(dict) cdef object _sens_cache = WeakKeyDefaultDict(dict) cdef object _leveldecl_cache = WeakKeyDefaultDict(dict) # # Classes # cdef list expand_cat_range(SELinuxPolicy policy, Category low, Category high): """ Helper function to expand a category range, e.g. c0.c1023 into the full set of categories by using the low and high categories of the set. """ cdef list expanded expanded = [low, high] for value in range(low._value, high._value): expanded.append(Category.factory(policy, policy.category_value_to_datum(value))) return expanded cdef class Category(PolicySymbol): """An MLS category.""" cdef: readonly uint32_t _value list _aliases @staticmethod cdef inline Category factory(SELinuxPolicy policy, sepol.cat_datum_t *symbol): """Factory function for creating Category objects.""" cdef Category c if not policy.mls: raise MLSDisabled try: return _cat_cache[policy][symbol] except KeyError: c = Category.__new__(Category) c.policy = policy c.key = symbol c.name = policy.category_value_to_name(symbol.s.value - 1) c._value = symbol.s.value c._aliases = policy.category_alias_map[symbol.s.value] _cat_cache[policy][symbol] = c return c def __hash__(self): return hash(self.name) def __lt__(self, other): # Comparison based on their index instead of their names. return self._value < other._value def aliases(self): """Generator that yields all aliases for this category.""" return iter(self._aliases) def statement(self): cdef: str stmt size_t count count = len(self._aliases) stmt = "category {0}".format(self.name) if count > 1: stmt += " alias {{ {0} }}".format(' '.join(self._aliases)) elif count == 1: stmt += " alias {0}".format(self._aliases[0]) stmt += ";" return stmt cdef class Sensitivity(PolicySymbol): """An MLS sensitivity""" cdef: readonly uint32_t _value list _aliases LevelDecl _leveldecl @staticmethod cdef inline Sensitivity factory(SELinuxPolicy policy, sepol.level_datum_t *symbol): """Factory function for creating Sensitivity objects.""" cdef Sensitivity s if not policy.mls: raise MLSDisabled try: return _sens_cache[policy][symbol] except KeyError: s = Sensitivity.__new__(Sensitivity) _sens_cache[policy][symbol] = s s.policy = policy s.key = symbol s.name = policy.level_value_to_name(symbol.level.sens - 1) s._value = symbol.level.sens s._aliases = policy.sensitivity_alias_map[symbol.level.sens] return s def __hash__(self): return hash(self.name) def __ge__(self, other): return self._value >= other._value def __gt__(self, other): return self._value > other._value def __le__(self, other): return self._value <= other._value def __lt__(self, other): return self._value < other._value def aliases(self): """Generator that yields all aliases for this sensitivity.""" return iter(self._aliases) def level_decl(self): """Get the level declaration corresponding to this sensitivity.""" cdef sepol.level_datum_t *symbol = self.key if self._leveldecl is None: self._leveldecl = LevelDecl.factory(self.policy, symbol) return self._leveldecl def statement(self): cdef: str stmt size_t count count = len(self._aliases) stmt = "sensitivity {0}".format(self.name) if count > 1: stmt += " alias {{ {0} }}".format(' '.join(self._aliases)) elif count == 1: stmt += " alias {0}".format(self._aliases[0]) stmt += ";" return stmt cdef class BaseMLSLevel(PolicyObject): """Base class for MLS levels.""" cdef: set _categories readonly Sensitivity sensitivity def __str__(self): lvl = str(self.sensitivity) # sort by policy declaration order cats = sorted(self._categories, key=lambda k: k._value) if cats: # generate short category notation shortlist = [] for _, i in itertools.groupby(cats, key=lambda k, c=itertools.count(): k._value - next(c)): group = list(i) if len(group) > 1: shortlist.append("{0}.{1}".format(group[0], group[-1])) else: shortlist.append(str(group[0])) lvl += ":" + ','.join(shortlist) return lvl def categories(self): """ Generator that yields all individual categories for this level. All categories are yielded, not a compact notation such as c0.c255 """ return iter(self._categories) cdef class LevelDecl(BaseMLSLevel): """ The declaration statement for MLS levels, e.g: level s7:c0.c1023; """ @staticmethod cdef inline LevelDecl factory(SELinuxPolicy policy, sepol.level_datum_t *symbol): """Factory function for creating LevelDecl objects.""" cdef LevelDecl l if not policy.mls: raise MLSDisabled try: return _leveldecl_cache[policy][symbol] except KeyError: l = LevelDecl.__new__(LevelDecl) _leveldecl_cache[policy][symbol] = l l.policy = policy l._categories = set(CategoryEbitmapIterator.factory(policy, &symbol.level.cat)) # the datum for levels is also used for Sensitivity objects l.sensitivity = Sensitivity.factory(policy, symbol) return l def __hash__(self): return hash(self.sensitivity) # below comparisons are only based on sensitivity # dominance since, in this context, the allowable # category set is being defined for the level. # object type is asserted here because this cannot # be compared to a Level instance. def __eq__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" try: return self.sensitivity == other.sensitivity except AttributeError: return str(self) == str(other) def __ge__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity >= other.sensitivity def __gt__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity > other.sensitivity def __le__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity <= other.sensitivity def __lt__(self, other): assert not isinstance(other, Level), "Levels cannot be compared to level declarations" return self.sensitivity < other.sensitivity def statement(self): return "level {0};".format(self) cdef class Level(BaseMLSLevel): """ An MLS level used in contexts. The _sensitivity and _categories attributes are only populated if the level is user-generated. """ @staticmethod cdef inline Level factory(SELinuxPolicy policy, sepol.mls_level_t *symbol): """Factory function for creating Level objects.""" if not policy.mls: raise MLSDisabled cdef Level l = Level.__new__(Level) l.policy = policy l.sensitivity = Sensitivity.factory(policy, policy.level_value_to_datum(symbol.sens - 1)) l._categories = set(CategoryEbitmapIterator.factory(policy, &symbol.cat)) return l @staticmethod cdef inline Level factory_from_string(SELinuxPolicy policy, str name): """Factory function variant for constructing Level objects by a string.""" if not policy.mls: raise MLSDisabled cdef: Level l = Level.__new__(Level) list sens_split = name.split(":") str sens = sens_split[0] Sensitivity s list c str cats list catrange str group l.policy = policy try: l.sensitivity = policy.lookup_sensitivity(sens) except InvalidSensitivity as ex: raise InvalidLevel("{0} is not a valid level ({1} is not a valid sensitivity)". \ format(name, sens)) from ex l._categories = set() try: cats = sens_split[1] except IndexError: pass else: for group in cats.split(","): catrange = group.split(".") if len(catrange) == 2: try: l._categories.update(expand_cat_range(policy, policy.lookup_category(catrange[0]), policy.lookup_category(catrange[1]))) except InvalidCategory as ex: raise InvalidLevel( "{0} is not a valid level ({1} is not a valid category range)". format(name, group)) from ex elif len(catrange) == 1: try: l._categories.add(policy.lookup_category(catrange[0])) except InvalidCategory as ex: raise InvalidLevel("{0} is not a valid level ({1} is not a valid category)". format(name, group)) from ex else: raise InvalidLevel("{0} is not a valid level (level parsing error)".format(name)) # verify level is valid if not l <= l.sensitivity.level_decl(): raise InvalidLevel( "{0} is not a valid level (one or more categories are not associated with the " "sensitivity)".format(name)) return l def __hash__(self): return hash(str(self)) def __eq__(self, other): try: othercats = set(other.categories()) except AttributeError: return str(self) == str(other) else: return self.sensitivity == other.sensitivity and self._categories == othercats def __ge__(self, other): # Dom operator othercats = set(other.categories()) return self.sensitivity >= other.sensitivity and self._categories >= othercats def __gt__(self, other): othercats = set(other.categories()) return ((self.sensitivity > other.sensitivity and self._categories >= othercats) or (self.sensitivity >= other.sensitivity and self._categories > othercats)) def __le__(self, other): # Domby operator othercats = set(other.categories()) return self.sensitivity <= other.sensitivity and self._categories <= othercats def __lt__(self, other): othercats = set(other.categories()) return ((self.sensitivity < other.sensitivity and self._categories <= othercats) or (self.sensitivity <= other.sensitivity and self._categories < othercats)) def __xor__(self, other): # Incomp operator return not (self >= other or self <= other) def statement(self): raise NoStatement cdef class Range(PolicyObject): """An MLS range""" cdef: readonly Level low readonly Level high @staticmethod cdef inline Range factory(SELinuxPolicy policy, sepol.mls_range_t *symbol): """Factory function for creating Range objects.""" if not policy.mls: raise MLSDisabled cdef Range r = Range.__new__(Range) r.policy = policy r.low = Level.factory(policy, &symbol.level[0]) r.high = Level.factory(policy, &symbol.level[1]) return r @staticmethod cdef inline Range factory_from_string(SELinuxPolicy policy, str name): """Factory function variant for constructing Range objects by name.""" if not policy.mls: raise MLSDisabled cdef Range r = Range.__new__(Range) r.policy = policy # build range: cdef list levels = name.split("-") # strip() levels to handle ranges with spaces in them, # e.g. s0:c1 - s0:c0.c255 try: r.low = Level.factory_from_string(policy, levels[0].strip()) except InvalidLevel as ex: raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex try: r.high = Level.factory_from_string(policy, levels[1].strip()) except InvalidLevel as ex: raise InvalidRange("{0} is not a valid range ({1}).".format(name, ex)) from ex except IndexError: r.high = r.low # verify high level dominates low range if not r.high >= r.low: raise InvalidRange("{0} is not a valid range ({1.low} is not dominated by {1.high})". format(name, r)) return r def __str__(self): if self.high == self.low: return str(self.low) return "{0.low} - {0.high}".format(self) def __hash__(self): return hash(str(self)) def __eq__(self, other): try: return self.low == other.low and self.high == other.high except AttributeError: # remove all spaces in the string representations # to handle cases where the other object does not # have spaces around the '-' other_str = str(other).replace(" ", "") self_str = str(self).replace(" ", "") return self_str == other_str def __contains__(self, other): return self.low <= other <= self.high def statement(self): raise NoStatement # # Hash Table Iterators # cdef class CategoryHashtabIterator(HashtabIterator): """Iterate over categories in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating category iterators.""" i = CategoryHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() datum = self.curr.datum if self.curr else NULL while datum != NULL and datum.isalias: super().__next__() datum = self.curr.datum if self.curr else NULL return Category.factory(self.policy, datum) def __len__(self): cdef sepol.cat_datum_t *datum cdef sepol.hashtab_node_t *node cdef uint32_t bucket = 0 cdef size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and not datum.isalias: count += 1 node = node.next bucket += 1 return count def reset(self): super().reset() cdef sepol.cat_datum_t *datum = self.node.datum if self.node else NULL # advance over any attributes or aliases while datum != NULL and datum.isalias: self._next_node() if self.node == NULL or self.bucket >= self.table[0].size: break datum = self.node.datum if self.node else NULL cdef class SensitivityHashtabIterator(HashtabIterator): """Iterate over sensitivity in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating category iterators.""" i = SensitivityHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() datum = self.curr.datum if self.curr else NULL while datum != NULL and datum.isalias: super().__next__() datum = self.curr.datum if self.curr else NULL return Sensitivity.factory(self.policy, datum) def __len__(self): cdef sepol.level_datum_t *datum cdef sepol.hashtab_node_t *node cdef uint32_t bucket = 0 cdef size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and not datum.isalias: count += 1 node = node.next bucket += 1 return count def reset(self): super().reset() cdef sepol.level_datum_t *datum = self.node.datum if self.node else NULL # advance over any attributes or aliases while datum != NULL and datum.isalias: self._next_node() if self.node == NULL or self.bucket >= self.table[0].size: break datum = self.node.datum if self.node else NULL cdef class LevelDeclHashtabIterator(HashtabIterator): """Iterate over level declarations in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating level declarations iterators.""" i = LevelDeclHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() datum = self.curr.datum if self.curr else NULL while datum != NULL and datum.isalias: super().__next__() datum = self.curr.datum if self.curr else NULL return LevelDecl.factory(self.policy, datum) def __len__(self): cdef sepol.level_datum_t *datum cdef sepol.hashtab_node_t *node cdef uint32_t bucket = 0 cdef size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and not datum.isalias: count += 1 node = node.next bucket += 1 return count def reset(self): super().reset() cdef sepol.level_datum_t *datum = self.node.datum if self.node else NULL # advance over any attributes or aliases while datum != NULL and datum.isalias: self._next_node() if self.node == NULL or self.bucket >= self.table[0].size: break datum = self.node.datum if self.node else NULL # # Ebitmap Iterators # cdef class CategoryEbitmapIterator(EbitmapIterator): """Iterate over a category ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *symbol): """Factory function for creating CategoryEbitmapIterator.""" i = CategoryEbitmapIterator() i.policy = policy i.bmap = symbol i.reset() return i def __next__(self): super().__next__() return Category.factory(self.policy, self.policy.category_value_to_datum(self.bit)) setools-4.4.0/setools/policyrep/mlsrule.pxi000066400000000000000000000065451402045477700211360ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # class MLSRuletype(PolicyEnum): """An enumeration of MLS rule types.""" range_transition = 1 cdef class MLSRule(PolicyRule): """An MLS rule.""" cdef: readonly ObjClass tclass object rng @staticmethod cdef inline MLSRule factory(SELinuxPolicy policy, sepol.range_trans_t *symbol, sepol.mls_range_t *rng): """Factory function for creating MLSRule objects.""" cdef MLSRule r = MLSRule.__new__(MLSRule) r.policy = policy r.key = symbol r.ruletype = MLSRuletype.range_transition r.source = type_or_attr_factory(policy, policy.type_value_to_datum(symbol.source_type - 1)) r.target = type_or_attr_factory(policy, policy.type_value_to_datum(symbol.target_type - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(symbol.target_class - 1)) r.rng = Range.factory(policy, rng) r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|None|None".format(self)) def __lt__(self, other): return str(self) < str(other) @property def default(self): """The rule's default range.""" return self.rng def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef MLSRule r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = MLSRule.__new__(MLSRule) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.rng = self.rng r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default};".format(self) # # Iterators # cdef class MLSRuleIterator(HashtabIterator): """Iterate over MLS rules in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating MLS rule iterators.""" i = MLSRuleIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return MLSRule.factory(self.policy, self.curr.key, self.curr.datum) setools-4.4.0/setools/policyrep/netcontext.pxi000066400000000000000000000271061402045477700216420ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # IbpkeyconRange = collections.namedtuple("IbpkeyconRange", ["low", "high"]) PortconRange = collections.namedtuple("PortconRange", ["low", "high"]) # # Classes # cdef class Ibendportcon(Ocontext): """An ibendportcon statement.""" cdef: readonly str name readonly unsigned int port @staticmethod cdef inline Ibendportcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Ibendportcon objects.""" cdef Ibendportcon i = Ibendportcon.__new__(Ibendportcon) i.policy = policy i.key = symbol i.name = intern(symbol.u.ibendport.dev_name) i.port = symbol.u.ibendport.port i.context = Context.factory(policy, symbol.context) return i def __hash__(self): return hash("ibendportcon|{0.name}|{0.port}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "ibendportcon {0.name} {0.port} {0.context}".format(self) cdef class Ibpkeycon(Ocontext): """An ibpkeycon statement.""" cdef: readonly object subnet_prefix readonly object pkeys @staticmethod cdef inline Ibpkeycon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Ibpkeycon objects.""" cdef: Ibpkeycon i = Ibpkeycon.__new__(Ibpkeycon) char * prefix uint32_t *full_address i.policy = policy i.key = symbol i.pkeys = IbpkeyconRange(symbol.u.ibpkey.low_pkey, symbol.u.ibpkey.high_pkey) i.context = Context.factory(policy, symbol.context) # # The policy only stores the most significant 64bits of the subnet # prefix. Create a full IPv6 address for inet_ntop use # full_address = PyMem_Malloc(4 * sizeof(uint32_t)) if full_address == NULL: raise MemoryError memset(full_address, 0, 4 * sizeof(uint32_t)) memcpy(full_address, &symbol.u.ibpkey.subnet_prefix, sizeof(uint64_t)) # # Create IPv6Address object for the subnet prefix # prefix = PyMem_Malloc(INET6_ADDRSTRLEN * sizeof(char)) if prefix == NULL: PyMem_Free(full_address) raise MemoryError inet_ntop(AF_INET6, full_address, prefix, INET6_ADDRSTRLEN) i.subnet_prefix = ipaddress.IPv6Address(prefix) PyMem_Free(full_address) PyMem_Free(prefix) return i def __hash__(self): return hash("ibpkeycon|{0.subnet_prefix}|{0.pkeys.low}|{0.pkeys.high}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): if self.pkeys.low == self.pkeys.high: return "ibpkeycon {0.subnet_prefix} {0.pkeys.low:#x} {0.context}".format(self) else: return "ibpkeycon {0.subnet_prefix} {0.pkeys.low:#x}-{0.pkeys.high:#x} {0.context}". \ format(self) cdef class Netifcon(Ocontext): """A netifcon statement.""" cdef: readonly str netif readonly Context packet @staticmethod cdef inline Netifcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Netifcon objects.""" cdef Netifcon n = Netifcon.__new__(Netifcon) n.policy = policy n.key = symbol n.netif = intern(symbol.u.name) n.context = Context.factory(policy, symbol.context) n.packet = Context.factory(policy, &symbol.context[1]) return n def __hash__(self): return hash("netifcon|{0.netif}".format(self)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "netifcon {0.netif} {0.context} {0.packet}".format(self) class NodeconIPVersion(PolicyEnum): """Nodecon IP Version""" ipv4 = AF_INET ipv6 = AF_INET6 cdef class Nodecon(Ocontext): """A nodecon statement.""" cdef: readonly object ip_version readonly object network @staticmethod cdef inline Nodecon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol, ip_version): """Factory function for creating Nodecon objects.""" cdef: char * addr char * mask int CIDR = 0 int i uint32_t block Nodecon n = Nodecon.__new__(Nodecon) n.policy = policy n.key = symbol n.ip_version = ip_version n.context = Context.factory(policy, symbol.context) # # Retrieve address and netmask # addr = PyMem_Malloc(INET6_ADDRSTRLEN * sizeof(char)) if addr == NULL: raise MemoryError mask = PyMem_Malloc(INET6_ADDRSTRLEN * sizeof(char)) if mask == NULL: PyMem_Free(addr) raise MemoryError # # Build network object # # Python 3.4's IPv6Network constructor does not support # expanded netmasks, only CIDR numbers. Convert netmask # into CIDR. # This is Brian Kernighan's method for counting set bits. # If the netmask happens to be invalid, this will # not detect it. if ip_version == NodeconIPVersion.ipv4: # convert network order to string inet_ntop(AF_INET, &symbol.u.node.addr, addr, INET6_ADDRSTRLEN) inet_ntop(AF_INET, &symbol.u.node.mask, mask, INET6_ADDRSTRLEN) # count bits block = symbol.u.node.mask while block: block &= block - 1 CIDR += 1 else: # NodeconIPVersion.ipv6 # convert network order to string inet_ntop(AF_INET6, &symbol.u.node6.addr, addr, INET6_ADDRSTRLEN) inet_ntop(AF_INET6, &symbol.u.node6.mask, mask, INET6_ADDRSTRLEN) # count bits for i in range(4): block = symbol.u.node6.mask[i] while block: block &= block - 1 CIDR += 1 net_with_mask = "{0}/{1}".format(addr, CIDR) try: # checkpolicy does not verify that no host bits are set, # so strict will raise an exception if host bits are set. n.network = ipaddress.ip_network(net_with_mask) except ValueError as ex: log = logging.getLogger(__name__) log.warning("Nodecon with network {} {} has host bits set. Analyses may have " "unexpected results.".format(addr, mask)) n.network = ipaddress.ip_network(net_with_mask, strict=False) PyMem_Free(addr) PyMem_Free(mask) return n def __hash__(self): return hash("nodecon|{}".format(self.network.with_netmask)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): return "nodecon {1} {0.context}".format(self, self.network.with_netmask.replace("/", " ")) class PortconProtocol(PolicyEnum): """A portcon protocol type.""" tcp = IPPROTO_TCP udp = IPPROTO_UDP dccp = IPPROTO_DCCP sctp = IPPROTO_SCTP cdef class Portcon(Ocontext): """A portcon statement.""" cdef: readonly object ports readonly object protocol @staticmethod cdef inline Portcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Portcon objects.""" cdef Portcon p = Portcon.__new__(Portcon) p.policy = policy p.key = symbol p.ports = PortconRange(symbol.u.port.low_port, symbol.u.port.high_port) p.protocol = PortconProtocol(symbol.u.port.protocol) p.context = Context.factory(policy, symbol.context) return p def __hash__(self): return hash("portcon|{0.protocol}|{1.low}|{1.high}".format(self, self.ports)) def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def statement(self): low, high = self.ports if low == high: return "portcon {0.protocol} {1} {0.context}".format(self, low) else: return "portcon {0.protocol} {1}-{2} {0.context}".format(self, low, high) # # Iterators # cdef class IbendportconIterator(OcontextIterator): """Iterator for ibendportcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Ibendportcon iterators.""" i = IbendportconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Ibendportcon.factory(self.policy, self.ocon) cdef class IbpkeyconIterator(OcontextIterator): """Iterator for ibpkeycon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Ibpkeycon iterators.""" i = IbpkeyconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Ibpkeycon.factory(self.policy, self.ocon) cdef class NetifconIterator(OcontextIterator): """Iterator for netifcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Netifcon iterators.""" i = NetifconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Netifcon.factory(self.policy, self.ocon) cdef class NodeconIterator(OcontextIterator): """Iterator for nodecon statements in the policy.""" cdef object ip_version @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head, ip_version): """Factory function for creating Nodecon iterators.""" i = NodeconIterator() i.policy = policy i.head = i.curr = head i.ip_version = ip_version return i def __next__(self): super().__next__() return Nodecon.factory(self.policy, self.ocon, self.ip_version) cdef class PortconIterator(OcontextIterator): """Iterator for portcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Portcon iterators.""" i = PortconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Portcon.factory(self.policy, self.ocon) setools-4.4.0/setools/policyrep/objclass.pxi000066400000000000000000000224261402045477700212470ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef object _common_cache = WeakKeyDefaultDict(dict) cdef object _objclass_cache = WeakKeyDefaultDict(dict) # # Classes # cdef class Common(PolicySymbol): """A common permission set.""" cdef: dict _perm_table readonly frozenset perms @staticmethod cdef inline Common factory(SELinuxPolicy policy, sepol.common_datum_t *symbol): """Factory function for creating Common objects.""" cdef: Common c sepol.hashtab_node_t *node uint32_t bucket = 0 str key uint32_t value dict perm_table try: return _common_cache[policy][symbol] except KeyError: c = Common.__new__(Common) c.policy = policy c.key = symbol c.name = policy.common_value_to_name(symbol.s.value - 1) # # Create value:name permission table (reverse of what is in the policydb) # c._perm_table = {} while bucket < symbol.permissions.table[0].size: node = symbol.permissions.table[0].htable[bucket] while node != NULL: key = intern(node.key) value = (node.datum).s.value c._perm_table[value] = key node = node.next bucket += 1 c.perms = frozenset(c._perm_table.values()) _common_cache[policy][symbol] = c return c def __contains__(self, other): return other in self.perms def statement(self): return "common {0}\n{{\n\t{1}\n}}".format(self, '\n\t'.join(self.perms)) cdef class ObjClass(PolicySymbol): """An object class.""" cdef: Common _common dict _perm_table list _defaults list _constraints list _validatetrans readonly frozenset perms # class_datum_t->permissions.nprim # is needed for the permission iterator uint32_t nprim @staticmethod cdef inline ObjClass factory(SELinuxPolicy policy, sepol.class_datum_t *symbol): """Factory function for creating ObjClass objects.""" cdef: sepol.hashtab_node_t *node uint32_t bucket = 0 str key uint32_t value dict perm_table object com ObjClass c try: return _objclass_cache[policy][symbol] except KeyError: # # Instantiate object class # c = ObjClass.__new__(ObjClass) _objclass_cache[policy][symbol] = c c.policy = policy c.key = symbol c.nprim = symbol.permissions.nprim c.name = policy.class_value_to_name(symbol.s.value - 1) # # Load common # if symbol.comdatum: c._common = Common.factory(policy, symbol.comdatum) c._perm_table = {} # # Create value:name permission table (reverse of what is in the policydb) # while bucket < symbol.permissions.table[0].size: node = symbol.permissions.table[0].htable[bucket] while node != NULL: key = intern(node.key) value = (node.datum).s.value c._perm_table[value] = key node = node.next bucket += 1 c.perms = frozenset(c._perm_table.values()) # # Load defaults # c._defaults = [] if symbol.default_user: c._defaults.append(Default.factory(policy, c, symbol.default_user, None, None, None)) if symbol.default_role: c._defaults.append(Default.factory(policy, c, None, symbol.default_role, None, None)) if symbol.default_type: c._defaults.append(Default.factory(policy, c, None, None, symbol.default_type, None)) if symbol.default_range: c._defaults.append(Default.factory(policy, c, None, None, None, symbol.default_range)) return c def __contains__(self, other): try: if other in self.common.perms: return True except NoCommon: pass return other in self.perms @property def common(self): """ The common that the object class inherits. Exceptions: NoCommon The object class does not inherit a common. """ if self._common: return self._common else: raise NoCommon("{0} does not inherit a common.".format(self.name)) def constraints(self): """Iterator for the constraints that apply to this class.""" cdef sepol.class_datum_t *symbol = self.key if self._constraints is None: self._constraints = list(ConstraintIterator.factory(self.policy, self, symbol.constraints)) return iter(self._constraints) def defaults(self): """Iterator for the defaults for this object class.""" return iter(self._defaults) def statement(self): stmt = "class {0}\n".format(self.name) try: stmt += "inherits {0}\n".format(self.common) except NoCommon: pass # a class that inherits may not have additional permissions if len(self.perms) > 0: stmt += "{{\n\t{0}\n}}".format('\n\t'.join(self.perms)) return stmt def validatetrans(self): """Iterator for validatetrans that apply to this class.""" cdef sepol.class_datum_t *symbol = self.key if self._validatetrans is None: self._validatetrans = list(ValidatetransIterator.factory(self.policy, self, symbol.validatetrans)) return iter(self._validatetrans) # # Iterators # cdef class CommonHashtabIterator(HashtabIterator): """Iterate over commons in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Role iterators.""" i = CommonHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return Common.factory(self.policy, self.curr.datum) cdef class ObjClassHashtabIterator(HashtabIterator): """Iterate over roles in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Role iterators.""" i = ObjClassHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return ObjClass.factory(self.policy, self.curr.datum) cdef class PermissionVectorIterator(PolicyIterator): """Iterate over an access (permission) vector""" cdef: uint32_t vector uint32_t curr uint32_t perm_max dict perm_table @staticmethod cdef factory(SELinuxPolicy policy, ObjClass tclass, uint32_t vector): """Factory method for access vectors.""" cdef Common com i = PermissionVectorIterator() i.policy = policy i.vector = vector i.perm_max = tclass.nprim i.perm_table = tclass._perm_table.copy() try: com = tclass.common i.perm_table.update(com._perm_table) except NoCommon: pass i.reset() return i def __next__(self): cdef str name if not self.curr < self.perm_max: raise StopIteration name = self.perm_table[self.curr + 1] self.curr += 1 while self.curr < self.perm_max and not self.vector & (1 << self.curr): self.curr += 1 return name def __len__(self): cdef: uint32_t count = 0 uint32_t curr = 0 while curr < self.perm_max: if self.vector & (1 << curr): count += 1 def reset(self): """Reset the iterator back to the start.""" self.curr = 0 while self.curr < self.perm_max and not self.vector & (1 << self.curr): self.curr += 1 setools-4.4.0/setools/policyrep/object.pxi000066400000000000000000000171671402045477700207230ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Classes # cdef class PolicyObject: """This is a base class for all policy objects.""" cdef: readonly SELinuxPolicy policy uintptr_t key def __hash__(self): return hash(str(self)) def __copy__(self): # Do not copy. return self def __deepcopy__(self, memo): # Do not copy. memo[id(self)] = self return self def __eq__(self, other): try: # This is a regular Python function, so it cannot # access the other.key (C) attribute since it is not # a public attribute. return self._eq(other) except TypeError: return str(self) == str(other) cdef inline bint _eq(self, PolicyObject other): """ Low-level equality check for policy objects (C pointers). Exceptions: TypeError other is not a PolicyObject. """ return self.key == other.key def __ne__(self, other): return not self == other def __lt__(self, other): # this is used by Python sorting functions return str(self) < str(other) def __str__(self): return self.statement() def __repr__(self): return "<{0.__class__.__name__}({1}, \"{0}\")>".format(self, repr(self.policy)) def statement(self): """ A rendering of the policy statement. This should be overridden by subclasses. """ raise NotImplementedError cdef class PolicySymbol(PolicyObject): """Base class for policy symbols (declared objects: types, users, etc.)""" cdef readonly str name def __str__(self): return self.name cdef class Ocontext(PolicyObject): """Base class for most in-policy labeling statements, (portcon, nodecon, etc.)""" cdef readonly Context context # # Iterator classes # cdef class PolicyIterator: """Base class for all policy object iterators.""" cdef SELinuxPolicy policy def __iter__(self): return self def __next__(self): raise NotImplementedError def __len__(self): raise NotImplementedError def reset(self): """Reset the iterator to the start.""" raise NotImplementedError cdef class EbitmapIterator(PolicyIterator): """ Base class for iterators over hash tables. Sublcasses must provide their own __next__, which calls this class's __next__ and then uses a factory function to build and return an object from self.curr. For example: def __next__(self): super().__next__() return iomemcon_factory(self.policy, self.curr) """ cdef: sepol.ebitmap_t *bmap sepol.ebitmap_node_t *node size_t curr size_t bit def __next__(self): if self.curr >= self.bmap.highbit: raise StopIteration # Returning the object is delegated # to subclasses which should returning # the object based off of self.bit self.bit = self.curr self.curr = sepol.ebitmap_next(&self.node, self.curr) while self.curr < self.bmap.highbit and not sepol.ebitmap_node_get_bit(self.node, self.curr): self.curr = sepol.ebitmap_next(&self.node, self.curr) def __len__(self): cdef: sepol.ebitmap_node_t *node size_t curr size_t count = 0 count = 0 curr = sepol.ebitmap_start(self.bmap, &node) while curr < self.bmap.highbit: count += sepol.ebitmap_node_get_bit(node, curr) curr = sepol.ebitmap_next(&node, curr) return count def reset(self): """Reset the iterator back to the start.""" self.curr = sepol.ebitmap_start(self.bmap, &self.node) # advance to first set bit while self.curr < self.bmap.highbit and not sepol.ebitmap_node_get_bit(self.node, self.curr): self.curr = sepol.ebitmap_next(&self.node, self.curr) cdef class HashtabIterator(PolicyIterator): """ Base class for iterators over hash tables. Sublcasses must provide their own __next__, which calls this class's __next__ and then uses a factory function to build and return an object from self.curr. For example: def __next__(self): super().__next__() return iomemcon_factory(self.policy, self.curr) """ cdef: sepol.hashtab_t *table sepol.hashtab_node_t *node sepol.hashtab_node_t *curr unsigned int bucket cdef void _next_bucket(self): """Internal method for advancing to the next bucket.""" self.bucket += 1 if self.bucket < self.table[0].size: self.node = self.table[0].htable[self.bucket] else: self.node = NULL cdef void _next_node(self): """Internal method for advancing to the next node.""" if self.node != NULL and self.node.next != NULL: self.node = self.node.next else: self._next_bucket() while self.bucket < self.table[0].size and self.node == NULL: self._next_bucket() def __next__(self): # # Note: cython does not support the regular C pointer # dereferencing (e.g. *ptr), so the ptr[0] way is used below # to dereference self.table. # if self.table[0] == NULL or self.table[0].nel == 0 or self.bucket >= self.table[0].size: raise StopIteration # Returning the object is delegated # to subclasses which should returning # the objects based off of # self.node.key and/or self.node.datum self.curr = self.node self._next_node() def __len__(self): return self.table[0].nel def reset(self): """Reset the iterator to the start.""" self.node = self.table[0].htable[0] # advance to first item if self.node == NULL: self._next_node() cdef class OcontextIterator(PolicyIterator): """ Base class for iterators for most in-policy labeling statements, (portcon, nodecon, etc.) Sublcasses must provide their own __next__, which calls this class's __next__ and then uses a factory function to build and return an object from self.ocon. For example: def __next__(self): super().__next__() return iomemcon_factory(self.policy, self.ocon) """ cdef: sepol.ocontext_t *head sepol.ocontext_t *ocon sepol.ocontext_t *curr def __next__(self): if self.curr == NULL: raise StopIteration # Returning the object is delegated # to subclasses which should returning # the ocon based off of self.ocon self.ocon = self.curr self.curr = self.curr.next def __len__(self): cdef: size_t count = 0 sepol.ocontext_t *ocon = self.head while ocon: count += 1 ocon = ocon.next return count setools-4.4.0/setools/policyrep/polcap.pxi000066400000000000000000000040111402045477700207130ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef class PolicyCapability(PolicySymbol): """A policy capability.""" @staticmethod cdef inline PolicyCapability factory(SELinuxPolicy policy, size_t bit): """Factory function for creating PolicyCapability objects.""" cdef PolicyCapability r = PolicyCapability.__new__(PolicyCapability) r.policy = policy r.name = intern(sepol.sepol_polcap_getname(bit)) return r def __eq__(self, other): try: return self.policy == other.policy \ and self.name == other.name except AttributeError: return self.name == str(other) def __hash__(self): return hash(self.name) def statement(self): return "policycap {0};".format(self) cdef class PolicyCapabilityIterator(EbitmapIterator): """Iterator for policy capability statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *bmap): """Factory function for creating PolicyCapability iterators.""" i = PolicyCapabilityIterator() i.policy = policy i.bmap = bmap i.reset() return i def __next__(self): super().__next__() return PolicyCapability.factory(self.policy, self.bit) setools-4.4.0/setools/policyrep/rbacrule.pxi000066400000000000000000000152211402045477700212410ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Typing # AnyRBACRule = Union[RoleAllow, RoleTransition] # # Classes # class RBACRuletype(PolicyEnum): """An enumeration of RBAC rule types.""" allow = 1 role_transition = 2 cdef class RoleAllow(PolicyRule): """A role allow rule.""" @staticmethod cdef inline RoleAllow factory(SELinuxPolicy policy, sepol.role_allow_t *symbol): """Factory function for creating RoleAllow objects.""" cdef RoleAllow r = RoleAllow.__new__(RoleAllow) r.policy = policy r.key = symbol r.ruletype = RBACRuletype.allow r.source = Role.factory(policy, policy.role_value_to_datum(symbol.role - 1)) r.target = Role.factory(policy, policy.role_value_to_datum(symbol.new_role - 1)) r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}".format(self)) def __lt__(self, other): return str(self) < str(other) @property def tclass(self): """The rule's object class.""" raise RuleUseError("Role allow rules do not have an object class.") @property def default(self): """The rule's default role.""" raise RuleUseError("Role allow rules do not have a default role.") def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef RoleAllow r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): """Factory function for creating ExpandedRoleAllow objects.""" r = RoleAllow.__new__(RoleAllow) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): return "{0.ruletype} {0.source} {0.target};".format(self) cdef class RoleTransition(PolicyRule): """A role_transition rule.""" cdef: readonly ObjClass tclass Role dft @staticmethod cdef inline RoleTransition factory(SELinuxPolicy policy, sepol.role_trans_t *symbol): """Factory function for creating RoleTransition objects.""" cdef RoleTransition r = RoleTransition.__new__(RoleTransition) r.policy = policy r.key = symbol r.ruletype = RBACRuletype.role_transition r.source = Role.factory(policy, policy.role_value_to_datum(symbol.role - 1)) r.target = type_or_attr_factory(policy, policy.type_value_to_datum(symbol.type - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(symbol.tclass - 1)) r.dft = Role.factory(policy, policy.role_value_to_datum(symbol.new_role - 1)) r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|None|None".format(self)) def __lt__(self, other): return str(self) < str(other) @property def default(self): """The rule's default role.""" return self.dft def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef RoleTransition r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = RoleTransition.__new__(RoleTransition) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.dft = self.dft r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default};".format(self) # # Iterators # cdef class RoleAllowIterator(PolicyIterator): """Role allow rule iterator.""" cdef: sepol.role_allow_t *head sepol.role_allow_t *curr @staticmethod cdef factory(SELinuxPolicy policy, sepol.role_allow_t *head): """Role allow rule iterator factory.""" i = RoleAllowIterator() i.policy = policy i.head = head i.reset() return i def __next__(self): if self.curr == NULL: raise StopIteration item = RoleAllow.factory(self.policy, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.role_allow_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head cdef class RoleTransitionIterator(PolicyIterator): """Role transition rule iterator.""" cdef: sepol.role_trans_t *head sepol.role_trans_t *curr @staticmethod cdef factory(SELinuxPolicy policy, sepol.role_trans_t *head): """Role transition rule iterator factory.""" i = RoleTransitionIterator() i.policy = policy i.head = head i.reset() return i def __next__(self): if self.curr == NULL: raise StopIteration item = RoleTransition.factory(self.policy, self.curr) self.curr = self.curr.next return item def __len__(self): cdef: sepol.role_trans_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head setools-4.4.0/setools/policyrep/role.pxi000066400000000000000000000060751402045477700204120ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef class Role(PolicySymbol): """A role.""" cdef frozenset _types @staticmethod cdef inline Role factory(SELinuxPolicy policy, sepol.role_datum_t *symbol): """Factory function for creating Role objects.""" cdef Role r = Role.__new__(Role) r.policy = policy r.key = symbol r.name = policy.role_value_to_name(symbol.s.value - 1) r._types = frozenset(TypeEbitmapIterator.factory_from_set(policy, &symbol.types)) return r @property def dominated_roles(self): """The roles that this role dominates.""" # TODO: do dominated roles even work? #return set(RoleEbitmapIterator.factory(self.policy, &self.handle.dominates)) return frozenset() def expand(self): """Generator that expands this into its member roles.""" yield self def types(self): """Generator which yields the role's set of types.""" return iter(self._types) def statement(self): cdef size_t count types = list(str(t) for t in self._types) count = len(types) stmt = "role {0}".format(self) if count == 1: stmt += " types {0}".format(types[0]) else: stmt += " types {{ {0} }}".format(' '.join(types)) stmt += ";" return stmt # # Iterator Classes # cdef class RoleHashtabIterator(HashtabIterator): """Iterate over roles in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Role iterators.""" i = RoleHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return Role.factory(self.policy, self.curr.datum) cdef class RoleEbitmapIterator(EbitmapIterator): """Iterate over a role ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *bmap): """Factory function for creating Role ebitmap iterators.""" i = RoleEbitmapIterator() i.policy = policy i.bmap = bmap i.reset() return i def __next__(self): super().__next__() return Role.factory(self.policy, self.policy.role_value_to_datum(self.bit)) setools-4.4.0/setools/policyrep/rule.pxi000066400000000000000000000041071402045477700204120ustar00rootroot00000000000000# Copyright 2014, 2016, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef class PolicyRule(PolicyObject): """This is base class for policy rules.""" cdef: readonly object ruletype readonly object source readonly object target readonly object origin # This is initialized to False: readonly bint extended @property def conditional(self): """The conditional expression for this rule.""" # Most rule types cannot be conditional. raise RuleNotConditional @property def conditional_block(self): """The conditional block of the rule (T/F)""" # Most rule types cannot be conditional. raise RuleNotConditional def enabled(self, **kwargs): """ Determine if the rule is enabled, given the stated boolean values. Keyword Parameters: bool_name=True|False Each keyword parameter name corresponds to a Boolean name in the expression and the state to use in the evaluation. If a Boolean value is not set, its default value is used. Extra values are ignored. Return: bool """ # Most rule types cannot be conditional, thus are always enabled. return True def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" raise NotImplementedError setools-4.4.0/setools/policyrep/selinux.pxd000066400000000000000000000020351402045477700211230ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # Directly use libselinux rather than the Python bindings, since # only a few functions are needed. cdef extern from "": bint selinuxfs_exists() const char* selinux_current_policy_path() const char* selinux_binary_policy_path() char* selinux_boolean_sub(const char *boolean_name); setools-4.4.0/setools/policyrep/selinuxpolicy.pxi000066400000000000000000001117131402045477700223540ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016-2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # pylint: disable=too-many-public-methods class PolicyTarget(PolicyEnum): """Enumeration of policy targets.""" selinux = sepol.SEPOL_TARGET_SELINUX xen = sepol.SEPOL_TARGET_XEN class HandleUnknown(PolicyEnum): """Enumeration of handle unknown settings.""" deny = sepol.SEPOL_DENY_UNKNOWN allow = sepol.SEPOL_ALLOW_UNKNOWN reject = sepol.SEPOL_REJECT_UNKNOWN cdef class SELinuxPolicy: cdef: sepol.sepol_policydb *handle sepol.sepol_handle *sh sepol.cat_datum_t **cat_val_to_struct sepol.level_datum_t **level_val_to_struct object log object constraint_counts object terule_counts dict type_alias_map dict category_alias_map dict sensitivity_alias_map object __weakref__ # Public attributes: readonly str path readonly object handle_unknown readonly object target_platform readonly unsigned int version readonly bint mls def __cinit__(self, policyfile=None): """ Parameter: policyfile Path to a policy to open. """ self.sh = NULL self.handle = NULL self.cat_val_to_struct = NULL self.level_val_to_struct = NULL self.log = logging.getLogger(__name__) if policyfile: self._load_policy(policyfile) else: self._load_running_policy() def __dealloc__(self): PyMem_Free(self.cat_val_to_struct) PyMem_Free(self.level_val_to_struct) if self.handle != NULL: sepol.sepol_policydb_free(self.handle) if self.sh != NULL: sepol.sepol_handle_destroy(self.sh) def __repr__(self): return "".format(self.path) def __str__(self): return self.path def __copy__(self): # Do not copy. return self def __deepcopy__(self, memo): # Do not copy. memo[id(self)] = self return self # # Policy statistics # @property def allow_count(self): """The number of (type) allow rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.allow.value] @property def allowxperm_count(self): """The number of allowxperm rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.allowxperm.value] @property def auditallow_count(self): """The number of auditallow rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.auditallow.value] @property def auditallowxperm_count(self): """The number of auditallowxperm rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.auditallowxperm.value] @property def boolean_count(self): """The number of Booleans.""" return len(self.bools()) @property def category_count(self): """The number of categories.""" return sum(1 for _ in self.categories()) @property def class_count(self): """The number of object classes.""" return len(self.classes()) @property def common_count(self): """The number of common permission sets.""" return len(self.commons()) @property def conditional_count(self): """The number of conditionals.""" return len(self.conditionals()) @property def constraint_count(self): """The number of standard constraints.""" self._cache_constraint_counts() return self.constraint_counts[ConstraintRuletype.constrain] @property def default_count(self): """The number of default_* rules.""" return sum(1 for d in self.defaults()) @property def devicetreecon_count(self): """The number of Xen devicetreecon statements.""" return len(self.devicetreecons()) @property def dontaudit_count(self): """The number of dontaudit rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.dontaudit.value] @property def dontauditxperm_count(self): """The number of dontauditxperm rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.dontauditxperm.value] @property def fs_use_count(self): """The number of fs_use_* statements.""" return len(self.fs_uses()) @property def genfscon_count(self): """The number of genfscon statements.""" return len(self.genfscons()) @property def ibendportcon_count(self): """The number of ibendportcon statements.""" return len(self.ibendportcons()) @property def ibpkeycon_count(self): """The number of ibpkeycon statements.""" return len(self.ibpkeycons()) @property def initialsids_count(self): """The number of initial sid statements.""" return len(self.initialsids()) @property def iomemcon_count(self): """The number of Xen iomemcon statements.""" return len(self.iomemcons()) @property def ioportcon_count(self): """The number of Xen ioportcon statements.""" return len(self.ioportcons()) @property def level_count(self): """The number of levels.""" return sum(1 for _ in self.levels()) @property def mlsconstraint_count(self): """The number of MLS constraints.""" self._cache_constraint_counts() return self.constraint_counts[ConstraintRuletype.mlsconstrain] @property def mlsvalidatetrans_count(self): """The number of MLS validatetrans.""" self._cache_constraint_counts() return self.constraint_counts[ConstraintRuletype.mlsvalidatetrans] @property def netifcon_count(self): """The number of netifcon statements.""" return len(self.netifcons()) @property def neverallow_count(self): """The number of neverallow rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.neverallow.value] @property def neverallowxperm_count(self): """The number of neverallowxperm rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.neverallowxperm.value] @property def nodecon_count(self): """The number of nodecon statements.""" return sum(1 for n in self.nodecons()) @property def pcidevicecon_count(self): """The number of Xen pcidevicecon statements.""" return len(self.pcidevicecons()) @property def permission_count(self): """The number of permissions.""" return sum(len(c.perms) for c in itertools.chain(self.commons(), self.classes())) @property def permissives_count(self): """The number of permissive types.""" return sum(1 for t in self.types() if t.ispermissive) @property def pirqcon_count(self): """The number of Xen pirqcon statements.""" return len(self.pirqcons()) @property def polcap_count(self): """The number of policy capabilities.""" return len(self.polcaps()) @property def portcon_count(self): """The number of portcon statements.""" return len(self.portcons()) @property def role_allow_count(self): """The number of role allow rules.""" return len(RoleAllowIterator.factory(self, self.handle.p.role_allow)) @property def role_transition_count(self): """The number of role_transition rules.""" return len(RoleTransitionIterator.factory(self, self.handle.p.role_tr)) @property def range_transition_count(self): return sum(1 for r in self.mlsrules() if r.ruletype is MLSRuletype.range_transition) @property def role_count(self): """The number of roles.""" return len(self.roles()) @property def type_attribute_count(self): """The number of (type) attributes.""" return len(self.typeattributes()) @property def type_change_count(self): """The number of type_change rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.type_change.value] @property def type_count(self): """The number of types.""" return len(self.types()) @property def type_member_count(self): """The number of type_member rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.type_member.value] @property def type_transition_count(self): """The number of type_transition rules.""" self._cache_terule_counts() return self.terule_counts[TERuletype.type_transition.value] @property def typebounds_count(self): """The number of typebounds rules.""" return len(TypeboundsIterator.factory(self, &self.handle.p.symtab[sepol.SYM_TYPES].table)) @property def user_count(self): return len(self.users()) @property def validatetrans_count(self): """The number of validatetrans.""" self._cache_constraint_counts() return self.constraint_counts[ConstraintRuletype.validatetrans] # # Policy components lookup functions # def lookup_boolean(self, name): """Look up a Boolean.""" for b in self.bools(): if b == name: return b raise InvalidBoolean("{0} is not a valid Boolean".format(name)) def lookup_category(self, name, deref=True): """Look up a category, with optional alias dereferencing.""" for c in self.categories(): if c == name or (deref and name in list(c.aliases())): return c raise InvalidCategory("{0} is not a valid category".format(name)) def lookup_class(self, name): """Look up an object class.""" for cls in self.classes(): if cls == name: return cls raise InvalidClass("{0} is not a valid class".format(name)) def lookup_common(self, name): """Look up a common permission set.""" for common in self.commons(): if common == name: return common raise InvalidCommon("{0} is not a valid common".format(name)) def lookup_initialsid(self, name): """Look up an initial sid.""" for sid in self.initialsids(): if sid == name: return sid raise InvalidInitialSid("{0} is not a valid initial SID".format(name)) def lookup_level(self, level): """Look up a MLS level.""" return Level.factory_from_string(self, level) def lookup_sensitivity(self, name, deref=True): """Look up a MLS sensitivity by name, with optional alias dereferencing.""" for s in self.sensitivities(): if s == name or (deref and name in list(s.aliases())): return s raise InvalidSensitivity("{0} is not a valid sensitivity".format(name)) def lookup_range(self, range_): """Look up a MLS range.""" return Range.factory_from_string(self, range_) def lookup_role(self, name): """Look up a role by name.""" for r in self.roles(): if r == name: return r raise InvalidRole("{0} is not a valid role".format(name)) def lookup_type(self, name, deref=True): """Look up a type by name, with optional alias dereferencing.""" for t in self.types(): if t == name or (deref and name in list(t.aliases())): return t raise InvalidType("{0} is not a valid type".format(name)) def lookup_type_or_attr(self, name, deref=True): """Look up a type or type attribute by name, with optional alias dereferencing.""" for t in self.types(): if t == name or (deref and name in list(t.aliases())): return t for t in self.typeattributes(): if t == name: return t raise InvalidType("{0} is not a valid type attribute".format(name)) def lookup_typeattr(self, name): """Look up a type attribute by name.""" for t in self.typeattributes(): if t == name: return t raise InvalidType("{0} is not a valid type attribute".format(name)) def lookup_user(self, name): """Look up a user by name.""" for u in self.users(): if u == name: return u raise InvalidUser("{0} is not a valid user".format(name)) # # Policy components iterators # def bools(self): """Iterator which yields all Booleans.""" return BooleanHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_BOOLS].table) def bounds(self): """Iterator which yields all *bounds statements (typebounds, etc.)""" return TypeboundsIterator.factory(self, &self.handle.p.symtab[sepol.SYM_TYPES].table) def categories(self): """Iterator which yields all MLS categories.""" return CategoryHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_CATS].table) def classes(self): """Iterator which yields all object classes.""" return ObjClassHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_CLASSES].table) def commons(self): """Iterator which yields all commons.""" return CommonHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_COMMONS].table) def defaults(self): """Iterator over all default_* statements.""" for cls in ObjClassHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_CLASSES].table): yield from cls.defaults() def levels(self): """Iterator which yields all level declarations.""" return LevelDeclHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_LEVELS].table) def polcaps(self): """Iterator which yields all policy capabilities.""" return PolicyCapabilityIterator.factory(self, &self.handle.p.policycaps) def roles(self): """Iterator which yields all roles.""" return RoleHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_ROLES].table) def sensitivities(self): """Iterator over all sensitivities.""" return SensitivityHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_LEVELS].table) def types(self): """Iterator over all types.""" return TypeHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_TYPES].table) def typeattributes(self): """Iterator over all (type) attributes.""" return TypeAttributeHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_TYPES].table) def users(self): """Iterator which yields all roles.""" return UserHashtabIterator.factory(self, &self.handle.p.symtab[sepol.SYM_USERS].table) # # Policy rules iterators # def conditionals(self): """Iterator over all conditional rule blocks.""" return ConditionalIterator.factory(self, self.handle.p.cond_list) def mlsrules(self): """Iterator over all MLS rules.""" return MLSRuleIterator.factory(self, &self.handle.p.range_tr) def rbacrules(self): """Iterator over all RBAC rules.""" return itertools.chain(RoleAllowIterator.factory(self, self.handle.p.role_allow), RoleTransitionIterator.factory(self, self.handle.p.role_tr)) def terules(self): """Iterator over all type enforcement rules.""" yield from TERuleIterator.factory(self, &self.handle.p.te_avtab) yield from FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans) for c in self.conditionals(): yield from c.true_rules() yield from c.false_rules() # # Constraints iterators # def constraints(self): """Iterator over all constraints (regular and MLS).""" for c in self.classes(): yield from c.constraints() yield from c.validatetrans() # # In-policy Labeling statement iterators # def fs_uses(self): """Iterator over all fs_use_* statements.""" return FSUseIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_FSUSE]) def genfscons(self): """Iterator over all genfscon statements.""" return GenfsconIterator.factory(self, self.handle.p.genfs) def ibendportcons(self): """Iterator over all ibendportcon statements.""" return IbendportconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_IBENDPORT]) def ibpkeycons(self): """Iterator over all ibpkeycon statements.""" return IbpkeyconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_IBPKEY]) def initialsids(self): """Iterator over all initial SID statements.""" return InitialSIDIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_ISID]) def netifcons(self): """Iterator over all netifcon statements.""" return NetifconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_NETIF]) def nodecons(self): """Iterator over all nodecon statements.""" return itertools.chain(NodeconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_NODE], NodeconIPVersion.ipv4), NodeconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_NODE6], NodeconIPVersion.ipv6)) def portcons(self): """Iterator over all portcon statements.""" return PortconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_PORT]) # # Xen labeling iterators # def devicetreecons(self): """Iterator over all devicetreecon statements.""" return DevicetreeconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_XEN_DEVICETREE]) def iomemcons(self): """Iterator over all iomemcon statements.""" return IomemconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_XEN_IOMEM]) def ioportcons(self): """Iterator over all ioportcon statements.""" return IoportconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_XEN_IOPORT]) def pcidevicecons(self): """Iterator over all pcidevicecon statements.""" return PcideviceconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_XEN_PCIDEVICE]) def pirqcons(self): """Iterator over all pirqcon statements.""" return PirqconIterator.factory(self, self.handle.p.ocontexts[sepol.OCON_XEN_PIRQ]) # # Low-level methods # cdef inline sepol.cond_bool_datum_t* boolean_value_to_datum(self, size_t value): """Return the class datum for the specified class value.""" return self.handle.p.bool_val_to_struct[value] cdef inline str boolean_value_to_name(self, size_t value): """Return the name of the boolean by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_BOOLS][value]) cdef inline sepol.cat_datum_t* category_value_to_datum(self, size_t value): """Return the category datum for the specified category value.""" return self.cat_val_to_struct[value] cdef inline str category_value_to_name(self, size_t value): """Return the name of the category by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_CATS][value]) cdef inline sepol.class_datum_t* class_value_to_datum(self, size_t value): """Return the class datum for the specified class value.""" return self.handle.p.class_val_to_struct[value] cdef inline str class_value_to_name(self, size_t value): """Return the name of the class by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_CLASSES][value]) cdef inline str common_value_to_name(self, size_t value): """Return the name of the common by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_COMMONS][value]) cdef inline sepol.level_datum_t* level_value_to_datum(self, size_t value): """Return the level datum for the specified level value.""" return self.level_val_to_struct[value] cdef inline str level_value_to_name(self, size_t value): """Return the name of the level by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_LEVELS][value]) cdef inline sepol.role_datum_t* role_value_to_datum(self, size_t value): """Return the role datum for the specified role value.""" return self.handle.p.role_val_to_struct[value] cdef inline str role_value_to_name(self, size_t value): """Return the name of the role by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_ROLES][value]) cdef inline sepol.type_datum_t* type_value_to_datum(self, size_t value): """Return the type datum for the specified type value.""" return self.handle.p.type_val_to_struct[value] cdef inline str type_value_to_name(self, size_t value): """Return the name of the type/attribute by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_TYPES][value]) cdef inline sepol.user_datum_t* user_value_to_datum(self, size_t value): """Return the user datum for the specified user value.""" return self.handle.p.user_val_to_struct[value] cdef inline str user_value_to_name(self, size_t value): """Return the name of the user by its value.""" return intern(self.handle.p.sym_val_to_name[sepol.SYM_USERS][value]) # # Internal methods # cdef _load_policy(self, str filename): """Load the specified policy.""" cdef: sepol.sepol_policy_file_t *pfile = NULL FILE *infile = NULL self.log.info("Opening SELinux policy \"{0}\"".format(filename)) self.sh = sepol.sepol_handle_create() if self.sh == NULL: raise MemoryError sepol.sepol_msg_set_callback(self.sh, sepol_logging_callback, self.handle) if sepol.sepol_policydb_create(&self.handle) < 0: raise MemoryError if sepol.sepol_policy_file_create(&pfile) < 0: raise MemoryError infile = fopen(filename, "rb") if infile == NULL: PyErr_SetFromErrnoWithFilename(OSError, filename) sepol.sepol_policy_file_set_handle(pfile, self.sh) sepol.sepol_policy_file_set_fp(pfile, infile) if sepol.sepol_policydb_read(self.handle, pfile) < 0: raise InvalidPolicy("Invalid policy: {}. A binary policy must be specified. " "(use e.g. policy.{} or sepolicy) Source policies are not " "supported.".format(filename, sepol.sepol_policy_kern_vers_max())) fclose(infile) sepol.sepol_policy_file_free(pfile) # # Load policy properties # self.handle_unknown = HandleUnknown(self.handle.p.handle_unknown) self.target_platform = PolicyTarget(self.handle.p.target_platform) self.version = self.handle.p.policyvers self.mls = self.handle.p.mls # # (Re)create data structures # if self.handle.p.attr_type_map != NULL: self._rebuild_attrs_from_map() # if source policies are supported in the # future this should only run on the # kernel policy: #self._synthesize_attrs() self._set_permissive_flags() if self.mls: self._create_mls_val_to_struct() # # Create value to alias mappings # self._load_type_aliases() if self.mls: self._load_sensitivity_aliases() self._load_category_aliases() self.log.info("Successfully opened SELinux policy \"{0}\"".format(filename)) self.path = filename cdef _load_running_policy(self): """Try to load the current running policy.""" cdef: int min_ver = sepol.sepol_policy_kern_vers_min() int max_ver = sepol.sepol_policy_kern_vers_max() const char *base_policy_path = selinux.selinux_binary_policy_path() const char *current_policy_path = selinux.selinux_current_policy_path() list potential_policies = [] self.log.info("Attempting to locate current running policy.") self.log.debug("SELinuxfs exists: {}".format(selinux.selinuxfs_exists())) self.log.debug("Sepol version range: {}-{}".format(min_ver, max_ver)) self.log.debug("Current policy path: {}".format(current_policy_path if current_policy_path != NULL else None)) self.log.debug("Binary policy path: {}".format(base_policy_path if base_policy_path != NULL else None)) # first try libselinux for current policy if current_policy_path != NULL: potential_policies.append(current_policy_path) # look through the supported policy versions if base_policy_path != NULL: for version in range(max_ver, min_ver - 1, -1): potential_policies.append("{0}.{1}".format(base_policy_path, version)) self.log.debug("Potential policies: {}".format(potential_policies)) for filename in potential_policies: try: self._load_policy(filename) except OSError as err: if err.errno != ENOENT: raise else: break else: raise RuntimeError("Unable to locate an SELinux policy to load.") cdef _set_permissive_flags(self): """ Set permissive flag in type datums. This modifies the policydb. """ cdef: size_t bit sepol.ebitmap_node_t *node = NULL self.log.debug("Setting permissive flags in type datums.") bit = sepol.ebitmap_start(&self.handle.p.permissive_map, &node) while bit < sepol.ebitmap_length(&self.handle.p.permissive_map): if sepol.ebitmap_node_get_bit(node, bit): assert bit == self.handle.p.type_val_to_struct[bit - 1].s.value self.handle.p.type_val_to_struct[bit - 1].flags |= sepol.TYPE_FLAGS_PERMISSIVE bit = sepol.ebitmap_next(&node, bit) cdef _create_mls_val_to_struct(self): """Create *_val_to_struct arrays for categories and levels.""" cdef: sepol.cat_datum_t *cat_datum sepol.hashtab_node_t *node uint32_t bucket = 0 size_t bucket_len size_t map_len # # Create cat_val_to_struct (indexed by value -1) # self.log.debug("Creating cat_val_to_struct.") map_len = self.handle.p.symtab[sepol.SYM_CATS].table.nel bucket_len = self.handle.p.symtab[sepol.SYM_CATS].table[0].size self.cat_val_to_struct = PyMem_Malloc( map_len * sizeof(sepol.cat_datum_t*)) if self.cat_val_to_struct == NULL: raise MemoryError while bucket < bucket_len: node = self.handle.p.symtab[sepol.SYM_CATS].table[0].htable[bucket] while node != NULL: cat_datum = node.datum if cat_datum != NULL: self.cat_val_to_struct[cat_datum.s.value - 1] = cat_datum node = node.next bucket += 1 # # Create level_val_to_struct (indexed by value -1) # self.log.debug("Creating level_val_to_struct.") map_len = self.handle.p.symtab[sepol.SYM_LEVELS].table.nel bucket_len = self.handle.p.symtab[sepol.SYM_LEVELS].table[0].size bucket = 0 self.level_val_to_struct = PyMem_Malloc( map_len * sizeof(sepol.level_datum_t*)) if self.level_val_to_struct == NULL: raise MemoryError while bucket < bucket_len: node = self.handle.p.symtab[sepol.SYM_LEVELS].table[0].htable[bucket] while node != NULL: level_datum = node.datum if level_datum != NULL: self.level_val_to_struct[level_datum.level.sens - 1] = level_datum node = node.next bucket += 1 cdef _load_category_aliases(self): """Build map of aliases to categories""" cdef: sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_CATS].table sepol.cat_datum_t *datum sepol.hashtab_node_t *node uint32_t bucket = 0 list entry self.category_alias_map = dict() while bucket < table[0].size: node = table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum == NULL: continue entry = self.category_alias_map.setdefault(datum.s.value, list()) if datum.isalias: entry.append(intern(node.key)) node = node.next bucket += 1 cdef _load_sensitivity_aliases(self): """Build map of aliases to sensitivities""" cdef: sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_LEVELS].table sepol.level_datum_t *datum sepol.hashtab_node_t *node uint32_t bucket = 0 list entry self.sensitivity_alias_map = dict() while bucket < table[0].size: node = table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum == NULL: continue entry = self.sensitivity_alias_map.setdefault(datum.level.sens, list()) if datum.isalias: entry.append(intern(node.key)) node = node.next bucket += 1 cdef _load_type_aliases(self): """Build map of aliases to types""" cdef: sepol.hashtab_t *table = &self.handle.p.symtab[sepol.SYM_TYPES].table sepol.type_datum_t *datum sepol.hashtab_node_t *node uint32_t bucket = 0 list entry self.type_alias_map = dict() while bucket < table[0].size: node = table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum == NULL: continue entry = self.type_alias_map.setdefault(datum.s.value, list()) if type_is_alias(datum): entry.append(intern(node.key)) node = node.next bucket += 1 cdef _rebuild_attrs_from_map(self): """ Rebuilds data for the attributes and inserts them into the policydb. This function modifies the policydb. If names are missing for attributes, they are synthesized in the form @ttr where value is the value of the attribute as a 0-padded four digit number. """ cdef: size_t i, count int bit sepol.ebitmap_node_t *node = NULL sepol.type_datum_t *tmp_type char *tmp_name self.log.debug("Rebuilding attributes.") for i in range(self.handle.p.symtab[sepol.SYM_TYPES].nprim): tmp_type = self.handle.p.type_val_to_struct[i] # skip types if tmp_type.flavor != sepol.TYPE_ATTRIB: continue # Synthesize a name if it is missing if self.handle.p.sym_val_to_name[sepol.SYM_TYPES][i] == NULL: # synthesize name tmp_name = calloc(15, sizeof(char)) if tmp_name == NULL: raise MemoryError snprintf(tmp_name, 15, "@ttr%010zd", i + 1) self.handle.p.sym_val_to_name[sepol.SYM_TYPES][i] = tmp_name # do not free, memory is owned by policydb now. tmp_name = NULL # determine if attribute is empty bit = sepol.ebitmap_start(&self.handle.p.attr_type_map[i], &node) while bit < sepol.ebitmap_length(&self.handle.p.attr_type_map[i]): if sepol.ebitmap_node_get_bit(node, bit): break bit = sepol.ebitmap_next(&node, bit) else: # skip empty attributes continue # relink the attr_type_map ebitmap to the type datum tmp_type.types.node = self.handle.p.attr_type_map[i].node tmp_type.types.highbit = self.handle.p.attr_type_map[i].highbit # disconnect ebitmap from attr_type_map to avoid # double free on policy destroy self.handle.p.attr_type_map[i].node = NULL self.handle.p.attr_type_map[i].highbit = 0 # now go through each of the member types, and set # the reverse mapping bit = sepol.ebitmap_start(&tmp_type.types, &node) while bit < sepol.ebitmap_length(&tmp_type.types): if sepol.ebitmap_node_get_bit(node, bit): orig_type = self.handle.p.type_val_to_struct[bit] ebitmap_set_bit(&orig_type.types, tmp_type.s.value - 1, 1) bit = sepol.ebitmap_next(&node, bit) cdef _synthesize_attrs(self): """ Builds data for empty attributes and inserts them into the policydb. This function modifies the policydb. Names created for attributes are of the form @ttr where value is the value of the attribute as a 0-padded four digit number. This was pulled in from libqpol, but it doesn't seem necessary. """ cdef: size_t i char *tmp_name = NULL char *buff = NULL sepol.type_datum_t *tmp_type = NULL sepol.ebitmap_t tmp_bmap self.log.debug("Synthesizing missing attributes.") tmp_bmap.node = NULL tmp_bmap.highbit = 0 for i in range(self.handle.p.symtab[sepol.SYM_TYPES].nprim): if self.handle.p.type_val_to_struct[i] != NULL: continue tmp_name = calloc(15, sizeof(char)) if tmp_name == NULL: raise MemoryError snprintf(tmp_name, 15, "@ttr%010zd", i + 1) tmp_type = calloc(1, sizeof(sepol.type_datum_t)) if tmp_type == NULL: free(tmp_name) raise MemoryError tmp_type.primary = 1 tmp_type.flavor = sepol.TYPE_ATTRIB tmp_type.s.value = i + 1 tmp_type.types = tmp_bmap try: hashtab_insert(self.handle.p.symtab[sepol.SYM_TYPES].table, tmp_name, tmp_type) except Exception: free(tmp_name) free(tmp_type) raise self.handle.p.sym_val_to_name[sepol.SYM_TYPES][i] = tmp_name self.handle.p.type_val_to_struct[i] = tmp_type # memory now owned by policydb, do not free tmp_name = NULL tmp_type = NULL cdef _cache_constraint_counts(self): """Count all constraints in one iteration.""" if not self.constraint_counts: self.constraint_counts = collections.Counter(r.ruletype for r in self.constraints()) cdef _cache_terule_counts(self): """Count all TE rules in one iteration.""" if not self.terule_counts: self.terule_counts = TERuleIterator.factory(self, &self.handle.p.te_avtab).ruletype_count() self.terule_counts[TERuletype.type_transition.value] += \ len(FileNameTERuleIterator.factory(self, &self.handle.p.filename_trans)) for c in self.conditionals(): self.terule_counts.update(c.true_rules().ruletype_count()) self.terule_counts.update(c.false_rules().ruletype_count()) setools-4.4.0/setools/policyrep/sepol.pxd000066400000000000000000000466101402045477700205650ustar00rootroot00000000000000# Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t from libc.stdio cimport FILE cdef extern from "": cdef struct sepol_handle: pass ctypedef sepol_handle sepol_handle_t sepol_handle_t* sepol_handle_create() void sepol_handle_destroy(sepol_handle_t *sh) cdef extern from "": ctypedef void (*msg_callback)(void *varg, sepol_handle_t *handle, const char *fmt, ...) void sepol_msg_set_callback(sepol_handle * handle, msg_callback cb, void *cb_arg) cdef extern from "": cdef int SECURITY_FS_USE_XATTR cdef int SECURITY_FS_USE_TRANS cdef int SECURITY_FS_USE_TASK cdef int SECURITY_FS_USE_GENFS cdef int SECURITY_FS_USE_NONE cdef extern from "": cdef int SELINUX_MAGIC ctypedef char* sepol_security_context_t ctypedef uint32_t sepol_access_vector_t ctypedef uint16_t sepol_security_class_t ctypedef uint32_t sepol_security_id_t cdef extern from "": # # ebitmap_node_t # cdef struct ebitmap_node: uint32_t startbit uint64_t map ebitmap_node *next ctypedef ebitmap_node ebitmap_node_t # # ebitmap_t # cdef int MAPBIT cdef int MAPSIZE cdef struct ebitmap: ebitmap_node_t *node uint32_t highbit ctypedef ebitmap ebitmap_t # # ebitmap functions # void ebitmap_init(ebitmap_t * e) size_t ebitmap_length(ebitmap_t * e) unsigned int ebitmap_start(const ebitmap_t * e, ebitmap_node_t ** n) unsigned int ebitmap_next(ebitmap_node_t ** n, unsigned int bit) int ebitmap_node_get_bit(ebitmap_node_t * n, unsigned int bit) cdef extern from "": ctypedef char* hashtab_key_t ctypedef const char* const_hashtab_key_t ctypedef void* hashtab_datum_t # # hashtab_node_t/hashtab_ptr_t # cdef struct hashtab_node: hashtab_key_t key hashtab_datum_t datum hashtab_node * next ctypedef hashtab_node* hashtab_ptr_t ctypedef hashtab_node hashtab_node_t # # hashtab_t # ctypedef unsigned int (*hash_value_cb) (hashtab_val *, const_hashtab_key_t) ctypedef int (*keycmp_cb) (hashtab_val *, const_hashtab_key_t, const_hashtab_key_t) cdef struct hashtab_val: hashtab_ptr_t *htable unsigned int size uint32_t nel hash_value_cb hash_value keycmp_cb keycmp ctypedef hashtab_val hashtab_val_t ctypedef hashtab_val_t* hashtab_t cdef extern from "": # # symtab_datum_t # cdef struct symtab_datum: uint32_t value ctypedef symtab_datum symtab_datum_t # # symtab_t # ctypedef struct symtab_t: hashtab_t table uint32_t nprim cdef extern from "": # # avtab_key_t # cdef int AVTAB_ALLOWED cdef int AVTAB_AUDITALLOW cdef int AVTAB_AUDITDENY cdef int AVTAB_NEVERALLOW cdef int AVTAB_AV cdef int AVTAB_TRANSITION cdef int AVTAB_MEMBER cdef int AVTAB_CHANGE cdef int AVTAB_TYPE cdef int AVTAB_XPERMS_ALLOWED cdef int AVTAB_XPERMS_AUDITALLOW cdef int AVTAB_XPERMS_DONTAUDIT cdef int AVTAB_XPERMS_NEVERALLOW cdef int AVTAB_XPERMS cdef int AVTAB_ENABLED_OLD cdef int AVTAB_ENABLED cdef struct avtab_key: uint16_t source_type uint16_t target_type uint16_t target_class uint16_t specified ctypedef avtab_key avtab_key_t # # avtab_extended_perms_t # cdef int AVTAB_XPERMS_IOCTLFUNCTION cdef int AVTAB_XPERMS_IOCTLDRIVER cdef struct avtab_extended_perms: uint8_t specified uint8_t driver uint32_t perms[8] # 8 is hardcoded in the header ctypedef avtab_extended_perms avtab_extended_perms_t # # avtab_datum_t # cdef struct avtab_datum: uint32_t data avtab_extended_perms_t *xperms ctypedef avtab_datum avtab_datum_t # # avtab_ptr_t # cdef struct avtab_node: avtab_key_t key avtab_datum_t datum avtab_node *next void *parse_context unsigned merged ctypedef avtab_node* avtab_ptr_t # # avtab_t # cdef struct avtab: avtab_ptr_t *htable uint32_t nel uint32_t nslot uint32_t mask ctypedef avtab avtab_t cdef extern from "": # # mls_level_t # cdef struct mls_level: uint32_t sens ebitmap_t cat ctypedef mls_level mls_level_t # # mls_range_t # cdef struct mls_range: mls_level_t level[2] # 2 is hardcoded in the header (low == level[0], high == level[1]) ctypedef mls_range mls_range_t # # mls_semantic_cat_t # cdef struct mls_semantic_cat: uint32_t low uint32_t high mls_semantic_cat *next ctypedef mls_semantic_cat mls_semantic_cat_t # # mls_semantic_level # cdef struct mls_semantic_level: uint32_t sens mls_semantic_cat_t *cat ctypedef mls_semantic_level mls_semantic_level_t # # mls_semantic_range # cdef struct mls_semantic_range: mls_semantic_level_t level[2] ctypedef mls_semantic_range mls_semantic_range_t cdef extern from "": # # context_struct_t # cdef struct context_struct: uint32_t user uint32_t role uint32_t type mls_range_t range ctypedef context_struct context_struct_t cdef extern from "": # # sidtab_node_t/sidtab_ptr_t # cdef struct sidtab_node: sepol_security_id_t sid context_struct_t context sidtab_node *next ctypedef sidtab_node sidtab_node_t ctypedef sidtab_node* sidtab_ptr_t # # sidtab_t # cdef int SIDTAB_HASH_BITS cdef int SIDTAB_HASH_BUCKETS cdef int SIDTAB_HASH_MASK cdef int SIDTAB_SIZE ctypedef struct sidtab_t: sidtab_ptr_t *htable unsigned int nel unsigned int next_sid unsigned char shutdown cdef extern from "": cdef int COND_EXPR_MAXDEPTH cdef int COND_MAX_BOOLS # # cond_av_list_t # cdef struct cond_av_list: avtab_ptr_t node cond_av_list *next ctypedef cond_av_list cond_av_list_t # # cond_expr_t # cdef int COND_BOOL cdef int COND_NOT cdef int COND_OR cdef int COND_AND cdef int COND_XOR cdef int COND_EQ cdef int COND_NEQ cdef int COND_LAST cdef struct cond_expr: uint32_t expr_type uint32_t bool cond_expr *next ctypedef cond_expr cond_expr_t # # cond_node_t # cdef int COND_NODE_FLAGS_TUNABLE cdef struct cond_node: int cur_state cond_expr_t *expr cond_av_list_t *true_list cond_av_list_t *false_list avrule *avtrue_list avrule *avfalse_list unsigned int nbools uint32_t bool_ids[5] # TODO: COND_MAX_BOOLS=5 uint32_t expr_pre_comp cond_node *next uint32_t flags ctypedef cond_node cond_node_t ctypedef cond_node cond_list_t cdef extern from "": cdef int CEXPR_NOT cdef int CEXPR_AND cdef int CEXPR_OR cdef int CEXPR_ATTR cdef int CEXPR_NAMES cdef int CEXPR_USER cdef int CEXPR_ROLE cdef int CEXPR_TYPE cdef int CEXPR_TARGET cdef int CEXPR_XTARGET cdef int CEXPR_L1L2 cdef int CEXPR_L1H2 cdef int CEXPR_H1L2 cdef int CEXPR_H1H2 cdef int CEXPR_L1H1 cdef int CEXPR_L2H2 # # constraint_expr_t # cdef int CEXPR_EQ cdef int CEXPR_NEQ cdef int CEXPR_DOM cdef int CEXPR_DOMBY cdef int CEXPR_INCOMP cdef struct constraint_expr: uint32_t expr_type uint32_t attr uint32_t op ebitmap_t names type_set *type_names constraint_expr *next ctypedef constraint_expr constraint_expr_t # # constraint_node_t # cdef struct constraint_node: sepol_access_vector_t permissions constraint_expr_t *expr constraint_node *next ctypedef constraint_node constraint_node_t cdef extern from "": const char *sepol_polcap_getname(unsigned int capnum) cdef extern from "": # # class_perm_node_t # cdef struct class_perm_node: uint32_t tclass uint32_t data class_perm_node *next ctypedef class_perm_node class_perm_node_t # # role_set_t # cdef int ROLE_STAR cdef int ROLE_COMP cdef struct role_set: ebitmap_t roles uint32_t flags ctypedef role_set role_set_t # # type_set_t # cdef int TYPE_STAR cdef int TYPE_COMP cdef struct type_set: ebitmap_t types ebitmap_t negset uint32_t flags ctypedef type_set type_set_t # # av_extended_perms_t # cdef int AVRULE_XPERMS_IOCTLFUNCTION cdef int AVRULE_XPERMS_IOCTLDRIVER cdef int EXTENDED_PERMS_LEN cdef struct av_extended_perms: uint8_t specified uint8_t driver uint32_t perms[8] # TODO: EXTENDED_PERMS_LEN=8 ctypedef av_extended_perms av_extended_perms_t cdef bint xperm_test(size_t x, uint32_t *perms) # # avrule_t # cdef int AVRULE_ALLOWED cdef int AVRULE_AUDITALLOW cdef int AVRULE_AUDITDENY cdef int AVRULE_DONTAUDIT cdef int AVRULE_NEVERALLOW cdef int AVRULE_AV cdef int AVRULE_TRANSITION cdef int AVRULE_MEMBER cdef int AVRULE_CHANGE cdef int AVRULE_TYPE cdef int AVRULE_XPERMS_ALLOWED cdef int AVRULE_XPERMS_AUDITALLOW cdef int AVRULE_XPERMS_DONTAUDIT cdef int AVRULE_XPERMS_NEVERALLOW cdef int AVRULE_XPERMS cdef int RULE_SELF cdef struct avrule: uint32_t specified uint32_t flags type_set_t stypes type_set_t ttypes class_perm_node_t *perms av_extended_perms_t *xperms unsigned long line char *source_filename unsigned long source_line avrule *next ctypedef avrule avrule_t # # cat_datum_t # cdef struct cat_datum: symtab_datum_t s unsigned char isalias ctypedef cat_datum cat_datum_t # # common_datum_t # cdef struct common_datum: symtab_datum_t s symtab_t permissions ctypedef common_datum common_datum_t # # class_datum_t # cdef int DEFAULT_SOURCE cdef int DEFAULT_TARGET cdef int DEFAULT_SOURCE_LOW cdef int DEFAULT_SOURCE_HIGH cdef int DEFAULT_SOURCE_LOW_HIGH cdef int DEFAULT_TARGET_LOW cdef int DEFAULT_TARGET_HIGH cdef int DEFAULT_TARGET_LOW_HIGH cdef int DEFAULT_GLBLUB cdef struct class_datum: symtab_datum_t s char *comkey common_datum_t *comdatum symtab_t permissions constraint_node *constraints constraint_node *validatetrans char default_user char default_role char default_type char default_range ctypedef class_datum class_datum_t # # cond_bool_datum_t # cdef int COND_BOOL_FLAGS_TUNABLE cdef struct cond_bool_datum: # Boolean data type symtab_datum_t s int state uint32_t flags ctypedef cond_bool_datum cond_bool_datum_t # # filename_trans_key_t # cdef struct filename_trans_key: uint32_t ttype uint32_t tclass char *name ctypedef filename_trans_key filename_trans_key_t # # filename_trans_datum_t # cdef struct filename_trans_datum: ebitmap_t stypes uint32_t otype filename_trans_datum *next ctypedef filename_trans_datum filename_trans_datum_t # # genfs_t # cdef struct genfs: char* fstype ocontext* head genfs* next ctypedef genfs genfs_t # # level_datum_t # cdef struct level_datum: mls_level_t *level unsigned char isalias unsigned char defined ctypedef level_datum level_datum_t # # ocontext_t union u member structs # cdef struct ocontext_port: uint8_t protocol uint16_t low_port uint16_t high_port cdef struct ocontext_node: uint32_t addr # network order uint32_t mask # network order cdef struct ocontext_node6: uint32_t addr[4] # network order uint32_t mask[4] # network order cdef struct ocontext_iomem: uint64_t low_iomem uint64_t high_iomem cdef struct ocontext_ioport: uint32_t low_ioport uint32_t high_ioport cdef struct ocontext_ibpkey: uint64_t subnet_prefix uint16_t low_pkey uint16_t high_pkey cdef struct ocontext_ibendport: char *dev_name uint8_t port cdef union ocontext_u_union: char *name ocontext_port port ocontext_node node ocontext_node6 node6 uint32_t device uint16_t pirq ocontext_iomem iomem ocontext_ioport ioport ocontext_ibpkey ibpkey ocontext_ibendport ibendport # # ocontext_t v union # cdef union ocontext_v_union: uint32_t sclass uint32_t behavior # # ocontext_t # cdef int OCON_ISID cdef int OCON_FS cdef int OCON_PORT cdef int OCON_NETIF cdef int OCON_NODE cdef int OCON_FSUSE cdef int OCON_NODE6 cdef int OCON_IBPKEY cdef int OCON_IBENDPORT cdef int OCON_XEN_ISID cdef int OCON_XEN_PIRQ cdef int OCON_XEN_IOPORT cdef int OCON_XEN_IOMEM cdef int OCON_XEN_PCIDEVICE cdef int OCON_XEN_DEVICETREE cdef int OCON_NUM cdef struct ocontext: ocontext_u_union u ocontext_v_union v context_struct_t context[2] # 2 is hardcoded in the header sepol_security_id_t sid[2] # 2 is hardcoded in the header ocontext *next ctypedef ocontext ocontext_t # # perm_datum_t # cdef struct perm_datum: symtab_datum_t s ctypedef perm_datum perm_datum_t # # range_trans_t # cdef struct range_trans: uint32_t source_type uint32_t target_type uint32_t target_class ctypedef range_trans range_trans_t # # role_allow_t # cdef struct role_allow: uint32_t role uint32_t new_role role_allow *next ctypedef role_allow role_allow_t # # role_allow_rule_t # cdef struct role_allow_rule: role_set_t roles role_set_t new_roles role_allow_rule *next ctypedef role_allow_rule role_allow_rule_t # # role_datum_t # cdef int ROLE_ROLE cdef int ROLE_ATTRIB cdef struct role_datum: symtab_datum_t s ebitmap_t dominates type_set_t types ebitmap_t cache uint32_t bounds uint32_t flavor ebitmap_t roles ctypedef role_datum role_datum_t # # role_trans_t # cdef struct role_trans: uint32_t role uint32_t type uint32_t tclass uint32_t new_role role_trans *next ctypedef role_trans role_trans_t # # role_trans_rule_t # cdef struct role_trans_rule: role_set_t roles type_set_t types ebitmap_t classes uint32_t new_role role_trans_rule *next ctypedef role_trans_rule role_trans_rule_t # # type_datum_t # cdef int TYPE_TYPE cdef int TYPE_ATTRIB cdef int TYPE_ALIAS cdef int TYPE_FLAGS_PERMISSIVE cdef int TYPE_FLAGS_EXPAND_ATTR_TRUE cdef int TYPE_FLAGS_EXPAND_ATTR_FALSE cdef int TYPE_FLAGS_EXPAND_ATTR cdef struct type_datum: symtab_datum_t s uint32_t primary uint32_t flavor ebitmap_t types uint32_t flags uint32_t bounds ctypedef type_datum type_datum_t # # user_datum_t # cdef struct user_datum: symtab_datum_t s role_set_t roles mls_semantic_range_t range mls_semantic_level_t dfltlevel ebitmap_t cache mls_range_t exp_range mls_level_t exp_dfltlevel uint32_t bounds ctypedef user_datum user_datum_t # # Policy DB # cdef int POLICYDB_VERSION_MAX cdef int POLICYDB_VERSION_MIN cdef int SYM_COMMONS cdef int SYM_CLASSES cdef int SYM_ROLES cdef int SYM_TYPES cdef int SYM_USERS cdef int SYM_BOOLS cdef int SYM_LEVELS cdef int SYM_CATS cdef int SYM_NUM cdef struct policydb: 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 int mls symtab_t symtab[8] # TODO: SYM_NUM=8 char **sym_val_to_name[8] # TODO: SYM_NUM=8 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 avtab_t te_avtab cond_bool_datum_t **bool_val_to_struct # bools indexed by (value - 1) avtab_t te_cond_avtab cond_node *cond_list role_trans_t *role_tr role_allow_t *role_allow ocontext_t *ocontexts[9] # TODO: OCON_NUM=9 genfs_t *genfs hashtab_t range_tr hashtab_t filename_trans 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 ctypedef policydb policydb_t cdef extern from "": cdef struct sepol_policy_file: pass ctypedef sepol_policy_file sepol_policy_file_t cdef struct sepol_policydb: policydb p ctypedef sepol_policydb sepol_policydb_t cdef int SEPOL_DENY_UNKNOWN cdef int SEPOL_REJECT_UNKNOWN cdef int SEPOL_ALLOW_UNKNOWN cdef int SEPOL_TARGET_SELINUX cdef int SEPOL_TARGET_XEN cdef int sepol_policy_kern_vers_min() cdef int sepol_policy_kern_vers_max() int sepol_policydb_create(sepol_policydb_t ** p) int sepol_policy_file_create(sepol_policy_file_t ** pf) void sepol_policy_file_set_handle(sepol_policy_file_t * pf, sepol_handle_t * handle) void sepol_policy_file_set_fp(sepol_policy_file_t * pf, FILE * fp) int sepol_policydb_read(sepol_policydb_t * p, sepol_policy_file_t * pf) void sepol_policydb_free(sepol_policydb_t * p) void sepol_policy_file_free(sepol_policy_file_t * pf) setools-4.4.0/setools/policyrep/terule.pxi000066400000000000000000000611111402045477700207410ustar00rootroot00000000000000# Copyright 2014-2016, Tresys Technology, LLC # Copyright 2016-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Typing # AnyTERule = TypeVar("AnyTERule", bound=BaseTERule) # # Classes # class TERuletype(PolicyEnum): """Enumeration of types of TE rules.""" allow = sepol.AVTAB_ALLOWED neverallow = sepol.AVTAB_NEVERALLOW auditallow = sepol.AVTAB_AUDITALLOW dontaudit = sepol.AVTAB_AUDITDENY allowxperm = sepol.AVTAB_XPERMS_ALLOWED neverallowxperm = sepol.AVTAB_XPERMS_NEVERALLOW auditallowxperm = sepol.AVTAB_XPERMS_AUDITALLOW dontauditxperm = sepol.AVTAB_XPERMS_DONTAUDIT type_transition = sepol.AVTAB_TRANSITION type_change = sepol.AVTAB_CHANGE type_member = sepol.AVTAB_MEMBER cdef class BaseTERule(PolicyRule): """Base class for TE rules.""" cdef: readonly ObjClass tclass str rule_string Conditional _conditional bint _conditional_block @property def filename(self): """The type_transition rule's file name.""" # Since name type_transitions have a different # class, this is always an error. if self.ruletype == TERuletype.type_transition: raise TERuleNoFilename else: raise RuleUseError("{0} rules do not have file names".format(self.ruletype)) @property def conditional(self): """The rule's conditional expression.""" if self._conditional is None: raise RuleNotConditional else: return self._conditional @property def conditional_block(self): """ The conditional block of the rule (T/F) For example, if the policy looks like this: if ( the_conditional_expression ) { If the rule is here, this property is True } else { If the rule is here, this property is False } """ if self._conditional is None: raise RuleNotConditional else: return self._conditional_block def enabled(self, **kwargs): """ Determine if the rule is enabled, given the stated boolean values. Keyword Parameters: bool_name=True|False Each keyword parameter name corresponds to a Boolean name in the expression and the state to use in the evaluation. If a Boolean value is not set, its default value is used. Extra values are ignored. Return: bool """ if self._conditional is None: return True if self._conditional.evaluate(**kwargs): return self._conditional_block else: return not self._conditional_block cdef class AVRule(BaseTERule): """An access vector type enforcement rule.""" cdef readonly frozenset perms @staticmethod cdef inline AVRule factory(SELinuxPolicy policy, sepol.avtab_key_t *key, sepol.avtab_datum_t *datum, conditional, conditional_block): """Factory function for creating AVRule objects.""" cdef AVRule r = AVRule.__new__(AVRule) r.policy = policy r.key = key r.ruletype = TERuletype(key.specified & ~sepol.AVTAB_ENABLED) r.source = type_or_attr_factory(policy, policy.type_value_to_datum(key.source_type - 1)) r.target = type_or_attr_factory(policy, policy.type_value_to_datum(key.target_type - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(key.target_class - 1)) r.perms = frozenset(p for p in PermissionVectorIterator.factory(policy, r.tclass, ~datum.data if key.specified & sepol.AVTAB_AUDITDENY else datum.data)) r._conditional = conditional r._conditional_block = conditional_block r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{1}|{2}". format(self, self._conditional, self._conditional_block)) def __lt__(self, other): return str(self) < str(other) @property def default(self): """The rule's default type.""" raise RuleUseError("{0} rules do not have a default type.".format(self.ruletype)) def derive_expanded(self, BaseType source, BaseType target, perms): """Derive an expanded rule from source, target, and perms.""" cdef AVRule r if self.origin is not None: raise RuleUseError("{0} rule is already expanded.".format(self.ruletype)) if source is not self.source and source not in self.source: raise RuleUseError("{0} is not {1} and is not in {1}".format(source, self.source)) if target is not self.target and target not in self.target: raise RuleUseError("{0} is not {1} and is not in {1}".format(target, self.target)) # No reasonable perms check possible as perms can be disjoint # from self.perms when redundant perms are removed. r = AVRule.__new__(AVRule) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = source r.target = target r.tclass = self.tclass r.perms = frozenset(p for p in perms) r._conditional = self._conditional r._conditional_block = self._conditional_block r.origin = self return r def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef AVRule r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = AVRule.__new__(AVRule) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.perms = self.perms r._conditional = self._conditional r._conditional_block = self._conditional_block r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): if not self.rule_string: self.rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} ".format(self) # allow/dontaudit/auditallow/neverallow rules perms = self.perms if len(perms) > 1: self.rule_string += "{{ {0} }};".format(' '.join(sorted(perms))) else: # convert to list since sets cannot be indexed self.rule_string += "{0};".format(list(perms)[0]) try: self.rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) except RuleNotConditional: pass return self.rule_string cdef class IoctlSet(frozenset): """ A set with overridden string functions which compresses the output into ioctl ranges instead of individual elements. """ def __format__(self, spec): """ String formating. The standard formatting (no specification) will render the ranges of ioctls, space separated. The , option by itself will render the ranges of ioctls, comma separated Any other combination of formatting options will fall back to set's formatting behavior. """ # generate short permission notation perms = sorted(self) shortlist = [] for _, i in itertools.groupby(perms, key=lambda k, c=itertools.count(): k - next(c)): group = list(i) if len(group) > 1: shortlist.append("{0:#06x}-{1:#06x}".format(group[0], group[-1])) else: shortlist.append("{0:#06x}".format(group[0])) if not spec: return " ".join(shortlist) elif spec == ",": return ", ".join(shortlist) else: return super(IoctlSet, self).__format__(spec) def __str__(self): return "{0}".format(self) def __repr__(self): return "{{ {0:,} }}".format(self) def ranges(self): """ Return the number of ranges in the set. Main use is to determine if brackets need to be used in string output. """ return sum(1 for (_a, _b) in itertools.groupby( sorted(self), key=lambda k, c=itertools.count(): k - next(c))) cdef class AVRuleXperm(BaseTERule): """An extended permission access vector type enforcement rule.""" cdef: readonly IoctlSet perms readonly str xperm_type @staticmethod cdef inline AVRuleXperm factory(SELinuxPolicy policy, sepol.avtab_key_t *key, sepol.avtab_datum_t *datum, conditional, conditional_block): """Factory function for creating AVRuleXperm objects.""" cdef: str xperm_type sepol.avtab_extended_perms_t *xperms = datum.xperms set perms = set() size_t curr = 0 size_t len = sizeof(xperms.perms) * sepol.EXTENDED_PERMS_LEN # # Build permission set # while curr < len: if sepol.xperm_test(curr, xperms.perms): if xperms.specified & sepol.AVTAB_XPERMS_IOCTLFUNCTION: perms.add(xperms.driver << 8 | curr) elif xperms.specified & sepol.AVTAB_XPERMS_IOCTLDRIVER: perms.add(curr << 8) else: raise LowLevelPolicyError("Unknown extended permission: {}".format( xperms.specified)) curr += 1 # # Determine xperm type # if datum.xperms == NULL: raise LowLevelPolicyError("Extended permission information is NULL") if datum.xperms.specified == sepol.AVTAB_XPERMS_IOCTLFUNCTION \ or datum.xperms.specified == sepol.AVTAB_XPERMS_IOCTLDRIVER: xperm_type = intern("ioctl") else: raise LowLevelPolicyError("Unknown extended permission: {}".format( datum.xperms.specified)) # # Construct rule object # cdef AVRuleXperm r = AVRuleXperm.__new__(AVRuleXperm) r.policy = policy r.key = key r.ruletype = TERuletype(key.specified & ~sepol.AVTAB_ENABLED) r.source = type_or_attr_factory(policy, policy.type_value_to_datum(key.source_type - 1)) r.target = type_or_attr_factory(policy, policy.type_value_to_datum(key.target_type - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(key.target_class - 1)) r.perms = IoctlSet(perms) r.extended = True r.xperm_type = xperm_type r._conditional = conditional r._conditional_block = conditional_block r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{0.xperm_type}|{1}|{2}". format(self, self._conditional, self._conditional_block)) def __lt__(self, other): return str(self) < str(other) @property def default(self): """The rule's default type.""" raise RuleUseError("{0} rules do not have a default type.".format(self.ruletype)) def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef AVRuleXperm r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = AVRuleXperm.__new__(AVRuleXperm) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.perms = self.perms r.extended = True r.xperm_type = self.xperm_type r._conditional = self._conditional r._conditional_block = self._conditional_block r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): if not self.rule_string: self.rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.xperm_type} ". \ format(self) # generate short permission notation perms = self.perms if perms.ranges() > 1: self.rule_string += "{{ {0} }};".format(perms) else: self.rule_string += "{0};".format(perms) return self.rule_string cdef class TERule(BaseTERule): """A type_* type enforcement rule.""" cdef Type dft @staticmethod cdef inline TERule factory(SELinuxPolicy policy, sepol.avtab_key_t *key, sepol.avtab_datum_t *datum, conditional, conditional_block): """Factory function for creating TERule objects.""" cdef TERule r = TERule.__new__(TERule) r.policy = policy r.key = key r.ruletype = TERuletype(key.specified & ~sepol.AVTAB_ENABLED) r.source = type_or_attr_factory(policy, policy.type_value_to_datum(key.source_type - 1)) r.target = type_or_attr_factory(policy, policy.type_value_to_datum(key.target_type - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(key.target_class - 1)) r.dft = Type.factory(policy, policy.type_value_to_datum(datum.data - 1)) r.origin = None r._conditional = conditional r._conditional_block = conditional_block return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{1}|{2}|{3}".format( self, None, self._conditional, self._conditional_block)) def __lt__(self, other): return str(self) < str(other) @property def perms(self): """The rule's permission set.""" raise RuleUseError("{0} rules do not have a permission set.".format(self.ruletype)) @property def default(self): """The rule's default type.""" return self.dft def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef TERule r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = TERule.__new__(TERule) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.dft = self.dft r.origin = self r._conditional = self._conditional r._conditional_block = self._conditional_block yield r else: # this rule is already expanded. yield self def statement(self): if not self.rule_string: self.rule_string = "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default};". \ format(self) try: self.rule_string += " [ {0.conditional} ]:{0.conditional_block}".format(self) except RuleNotConditional: pass return self.rule_string cdef class FileNameTERule(BaseTERule): """A type_transition type enforcement rule with filename.""" cdef: Type dft readonly str filename @staticmethod cdef inline FileNameTERule factory(SELinuxPolicy policy, sepol.filename_trans_key_t *key, Type stype, size_t otype): """Factory function for creating FileNameTERule objects.""" cdef FileNameTERule r = FileNameTERule.__new__(FileNameTERule) r.policy = policy r.key = key r.ruletype = TERuletype.type_transition r.source = stype r.target = type_or_attr_factory(policy, policy.type_value_to_datum(key.ttype - 1)) r.tclass = ObjClass.factory(policy, policy.class_value_to_datum(key.tclass - 1)) r.dft = Type.factory(policy, policy.type_value_to_datum(otype - 1)) r.filename = intern(key.name) r.origin = None return r def __hash__(self): return hash("{0.ruletype}|{0.source}|{0.target}|{0.tclass}|{0.filename}|{1}|{2}".format( self, None, None)) def __lt__(self, other): return str(self) < str(other) @property def perms(self): """The rule's permission set.""" raise RuleUseError("{0} rules do not have a permission set.".format(self.ruletype)) @property def default(self): """The rule's default type.""" return self.dft def expand(self): """Expand the rule into an equivalent set of rules without attributes.""" cdef FileNameTERule r if self.origin is None: for s, t in itertools.product(self.source.expand(), self.target.expand()): r = FileNameTERule.__new__(FileNameTERule) r.policy = self.policy r.key = self.key r.ruletype = self.ruletype r.source = s r.target = t r.tclass = self.tclass r.dft = self.dft r.filename = self.filename r.origin = None r._conditional = self._conditional r._conditional_block = self._conditional_block r.origin = self yield r else: # this rule is already expanded. yield self def statement(self): return "{0.ruletype} {0.source} {0.target}:{0.tclass} {0.default} {0.filename};". \ format(self) # # Iterators # cdef class TERuleIterator(PolicyIterator): """Iterator for access vector tables.""" cdef: sepol.avtab_t *table sepol.avtab_ptr_t node unsigned int bucket object conditional object cond_block @staticmethod cdef factory(SELinuxPolicy policy, sepol.avtab *table): """Factory function for creating TERule iterators.""" i = TERuleIterator() i.policy = policy i.table = table i.reset() return i cdef void _next_bucket(self): """Internal method for advancing to the next bucket.""" self.bucket += 1 if self.bucket < self.table.nslot: self.node = self.table.htable[self.bucket] else: self.node = NULL cdef void _next_node(self): """Internal method for advancing to the next node.""" if self.node != NULL and self.node.next != NULL: self.node = self.node.next else: self._next_bucket() while self.bucket < self.table.nslot and self.node == NULL: self._next_bucket() def __next__(self): cdef: sepol.avtab_key_t *key sepol.avtab_datum_t *datum if self.table == NULL or self.table.nel == 0 or self.bucket >= self.table.nslot: raise StopIteration key = &self.node.key datum = &self.node.datum self._next_node() if key.specified & sepol.AVRULE_AV: return AVRule.factory(self.policy, key, datum, None, None) elif key.specified & sepol.AVRULE_TYPE: return TERule.factory(self.policy, key, datum, None, None) elif key.specified & sepol.AVRULE_XPERMS: return AVRuleXperm.factory(self.policy, key, datum, None, None) else: raise LowLevelPolicyError("Unknown AV rule type 0x{}".format(key.specified, '04x')) def __len__(self): return self.table.nel def ruletype_count(self): """ Determine the number of rules. Return: collections.Counter object keyed by TERuletype.value """ cdef: sepol.avtab_key_t *key sepol.avtab_ptr_t node uint32_t bucket = 0 count = collections.Counter() while bucket < self.table[0].nslot: node = self.table[0].htable[bucket] while node != NULL: key = &node.key if node else NULL if key != NULL: count[key.specified & ~sepol.AVTAB_ENABLED] += 1 node = node.next bucket += 1 return count def reset(self): """Reset the iterator to the start.""" self.node = self.table.htable[0] # advance to first item if self.node == NULL: self._next_node() cdef class ConditionalTERuleIterator(PolicyIterator): """Conditional TE rule iterator.""" cdef: sepol.cond_av_list_t *head sepol.cond_av_list_t *curr object conditional object conditional_block @staticmethod cdef factory(SELinuxPolicy policy, sepol.cond_av_list_t *head, conditional, cond_block): """ConditionalTERuleIterator iterator factory.""" c = ConditionalTERuleIterator() c.policy = policy c.head = head c.conditional = conditional c.conditional_block = cond_block c.reset() return c def __next__(self): if self.curr == NULL: raise StopIteration key = &self.curr.node.key datum = &self.curr.node.datum self.curr = self.curr.next if key.specified & sepol.AVRULE_AV: return AVRule.factory(self.policy, key, datum, self.conditional, self.conditional_block) elif key.specified & sepol.AVRULE_TYPE: return TERule.factory(self.policy, key, datum, self.conditional, self.conditional_block) elif key.specified & sepol.AVRULE_XPERMS: return AVRuleXperm.factory(self.policy, key, datum, self.conditional, self.conditional_block) else: raise LowLevelPolicyError("Unknown AV rule type 0x{}".format(key.specified, '04x')) def __len__(self): cdef: sepol.cond_av_list_t *curr size_t count = 0 curr = self.head while curr != NULL: count += 1 curr = curr.next return count def ruletype_count(self): """ Determine the number of rules. Return: collections.Counter object keyed by TERuletype.value """ cdef sepol.cond_av_list_t *curr count = collections.Counter() curr = self.head while curr != NULL: count[curr.node.key.specified & ~sepol.AVTAB_ENABLED] += 1 curr = curr.next return count def reset(self): """Reset the iterator back to the start.""" self.curr = self.head cdef class FileNameTERuleIterator(HashtabIterator): """Iterate over FileNameTERules in the policy.""" cdef: sepol.filename_trans_datum_t *datum TypeEbitmapIterator stypei @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating FileNameTERule iterators.""" i = FileNameTERuleIterator() i.policy = policy i.table = table i.reset() return i def _next_stype(self): while True: if self.datum == NULL: super().__next__() self.datum = self.curr.datum self.stypei = TypeEbitmapIterator.factory(self.policy, &self.datum.stypes) try: return next(self.stypei) except StopIteration: pass self.datum = self.datum.next if self.datum != NULL: self.stypei = TypeEbitmapIterator.factory(self.policy, &self.datum.stypes) def __next__(self): stype = self._next_stype() return FileNameTERule.factory(self.policy, self.curr.key, stype, self.datum.otype) def __len__(self): return sum(1 for r in FileNameTERuleIterator.factory(self.policy, self.table)) def reset(self): super().reset() self.datum = NULL setools-4.4.0/setools/policyrep/typeattr.pxi000066400000000000000000000304511402045477700213200ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017-2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Cache objects # cdef object _type_cache = WeakKeyDefaultDict(dict) cdef object _typeattr_cache = WeakKeyDefaultDict(dict) # # Typing # TypeOrAttr = TypeVar("TypeOrAttr", bound=BaseType) # # Type or attribute factory function # cdef inline BaseType type_or_attr_factory(SELinuxPolicy policy, sepol.type_datum_t *symbol): """Factory function for creating type or attribute objects.""" if symbol.flavor == sepol.TYPE_ATTRIB: return TypeAttribute.factory(policy, symbol) else: return Type.factory(policy, symbol) # # Classes # cdef class BaseType(PolicySymbol): """Type/attribute base class.""" def expand(self): """Generator that expands this attribute into its member types.""" raise NotImplementedError def attributes(self): """Generator that yields all attributes for this type.""" raise NotImplementedError def aliases(self): """Generator that yields all aliases for this type.""" raise NotImplementedError cdef class Type(BaseType): """A type.""" cdef: readonly object ispermissive list _aliases list _attrs # type_datum_t.s.value is needed by the # alias iterator uint32_t value @staticmethod cdef inline Type factory(SELinuxPolicy policy, sepol.type_datum_t *symbol): """Factory function for creating Type objects.""" cdef Type t if symbol.flavor != sepol.TYPE_TYPE: raise ValueError("{0} is not a type".format( policy.type_value_to_name(symbol.s.value - 1))) try: return _type_cache[policy][symbol] except KeyError: t = Type.__new__(Type) _type_cache[policy][symbol] = t t.policy = policy t.key = symbol t.value = symbol.s.value t.name = policy.type_value_to_name(symbol.s.value - 1) t.ispermissive = symbol.flags & sepol.TYPE_FLAGS_PERMISSIVE t._aliases = policy.type_alias_map[symbol.s.value] return t cdef inline void _load_attributes(self): """Helper method to load attributes.""" cdef sepol.type_datum_t *symbol = self.key if self._attrs is None: self._attrs = list(TypeAttributeEbitmapIterator.factory(self.policy, &symbol.types)) def expand(self): """Generator that expands this into its member types.""" yield self def attributes(self): """Generator that yields all attributes for this type.""" self._load_attributes() return iter(self._attrs) def aliases(self): """Generator that yields all aliases for this type.""" return iter(self._aliases) def statement(self): cdef: size_t count str stmt self._load_attributes() count = len(self._aliases) stmt = "type {0}".format(self.name) if count > 1: stmt += " alias {{ {0} }}".format(' '.join(self._aliases)) elif count == 1: stmt += " alias {0}".format(self._aliases[0]) for attr in self._attrs: stmt += ", {0}".format(attr) stmt += ";" return stmt cdef class TypeAttribute(BaseType): """A type attribute.""" cdef list _types @staticmethod cdef inline TypeAttribute factory(SELinuxPolicy policy, sepol.type_datum_t *symbol): """Factory function for creating TypeAttribute objects.""" cdef TypeAttribute a if symbol.flavor != sepol.TYPE_ATTRIB: raise ValueError("{0} is not an attribute".format( policy.type_value_to_name(symbol.s.value - 1))) try: return _typeattr_cache[policy][symbol] except KeyError: a = TypeAttribute.__new__(TypeAttribute) _typeattr_cache[policy][symbol] = a a.policy = policy a.key = symbol a.name = policy.type_value_to_name(symbol.s.value - 1) return a cdef load_types(self): cdef sepol.type_datum_t *symbol = self.key if self._types is None: self._types = list(TypeEbitmapIterator.factory(self.policy, &symbol.types)) def __contains__(self, other): self.load_types() return other in self._types def __iter__(self): self.load_types() return iter(self._types) def __len__(self): self.load_types() return len(self._types) def expand(self): """Generator that expands this attribute into its member types.""" self.load_types() return iter(self._types) def attributes(self): """Generator that yields all attributes for this type.""" raise SymbolUseError("{0} is an attribute, thus does not have attributes.".format( self.name)) def aliases(self): """Generator that yields all aliases for this type.""" raise SymbolUseError("{0} is an attribute, thus does not have aliases.".format(self.name)) @property def ispermissive(self): """(T/F) the type is permissive.""" raise SymbolUseError("{0} is an attribute, thus cannot be permissive.".format(self.name)) def statement(self): return "attribute {0};".format(self.name) # # Hash Table Iterator Classes # cdef inline bint type_is_alias(sepol.type_datum_t *datum): """Determine if the type datum is an alias.""" return (datum.primary == 0 and datum.flavor == sepol.TYPE_TYPE) \ or datum.flavor == sepol.TYPE_ALIAS cdef class TypeHashtabIterator(HashtabIterator): """Iterate over types in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Role iterators.""" i = TypeHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): cdef sepol.type_datum_t *datum super().__next__() datum = self.curr.datum while datum.flavor != sepol.TYPE_TYPE or type_is_alias(datum): super().__next__() datum = self.curr.datum return Type.factory(self.policy, datum) def __len__(self): cdef sepol.type_datum_t *datum cdef sepol.hashtab_node_t *node cdef uint32_t bucket = 0 cdef size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and datum.flavor == sepol.TYPE_TYPE and not type_is_alias(datum): count += 1 node = node.next bucket += 1 return count def reset(self): super().reset() # advance over any attributes or aliases while ( self.node.datum).flavor != sepol.TYPE_TYPE: self._next_node() cdef class TypeAttributeHashtabIterator(HashtabIterator): """Iterate over type attributes in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating Role iterators.""" i = TypeAttributeHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() while ( self.curr.datum).flavor != sepol.TYPE_ATTRIB: super().__next__() return TypeAttribute.factory(self.policy, self.curr.datum) def __len__(self): cdef sepol.type_datum_t *datum cdef sepol.hashtab_node_t *node cdef uint32_t bucket = 0 cdef size_t count = 0 while bucket < self.table[0].size: node = self.table[0].htable[bucket] while node != NULL: datum = node.datum if node else NULL if datum != NULL and datum.flavor == sepol.TYPE_ATTRIB: count += 1 node = node.next bucket += 1 return count def reset(self): super().reset() # advance over any attributes or aliases while self.node != NULL and ( self.node.datum).flavor != sepol.TYPE_ATTRIB: self._next_node() # # Ebitmap Iterator Classes # cdef class TypeEbitmapIterator(EbitmapIterator): """Iterate over a type ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *symbol): """Factory function for creating TypeEbitmapIterator.""" i = TypeEbitmapIterator() i.policy = policy i.bmap = symbol i.reset() return i @staticmethod cdef factory_from_set(SELinuxPolicy policy, sepol.type_set_t *symbol): """Factory function for creating TypeEbitmapIterator from a type set.""" if symbol.flags: warnings.warn("* or ~ in the type set; this is not implemented in SETools.") if symbol.negset.node != NULL: warnings.warn("Negations in the type set; this is not implemented in SETools.") return TypeEbitmapIterator.factory(policy, &symbol.types) def __next__(self): super().__next__() return Type.factory(self.policy, self.policy.type_value_to_datum(self.bit)) cdef class TypeAttributeEbitmapIterator(EbitmapIterator): """Iterate over a type attribute ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *bmap): """Factory function for creating TypeAttributeEbitmapIterator.""" i = TypeAttributeEbitmapIterator() i.policy = policy i.bmap = bmap i.reset() return i @staticmethod cdef factory_from_set(SELinuxPolicy policy, sepol.type_set_t *symbol): """Factory function for creating TypeAttributeEbitmapIterator from a type set.""" if symbol.flags: warnings.warn("* or ~ in the type set; this is not implemented in SETools.") if symbol.negset.node != NULL: warnings.warn("Negations in the type set; this is not implemented in SETools.") return TypeAttributeEbitmapIterator.factory(policy, &symbol.types) def __next__(self): super().__next__() return TypeAttribute.factory(self.policy, self.policy.type_value_to_datum(self.bit)) cdef class TypeOrAttributeEbitmapIterator(EbitmapIterator): """Iterate over a type or type attribute ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *bmap): """Factory function for creating TypeAttributeEbitmapIterator.""" i = TypeOrAttributeEbitmapIterator() i.policy = policy i.bmap = bmap i.reset() return i @staticmethod cdef factory_from_set(SELinuxPolicy policy, sepol.type_set_t *symbol): """Factory function for creating TypeAttributeEbitmapIterator from a type set.""" if symbol.flags: warnings.warn("* or ~ in the type set; this is not implemented in SETools.") if symbol.negset.node != NULL: warnings.warn("Negations in the type set; this is not implemented in SETools.") return TypeOrAttributeEbitmapIterator.factory(policy, &symbol.types) def __next__(self): super().__next__() return type_or_attr_factory(self.policy, self.policy.type_value_to_datum(self.bit)) setools-4.4.0/setools/policyrep/user.pxi000066400000000000000000000075451402045477700204320ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017-2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # cdef object _user_cache = WeakKeyDefaultDict(dict) cdef class User(PolicySymbol): """A user.""" cdef: readonly frozenset roles Level _level Range _range @staticmethod cdef inline User factory(SELinuxPolicy policy, sepol.user_datum_t *symbol): """Factory function for constructing User objects.""" cdef User u try: return _user_cache[policy][symbol] except KeyError: u = User.__new__(User) _user_cache[policy][symbol] = u u.policy = policy u.key = symbol u.name = policy.user_value_to_name(symbol.s.value - 1) # object_r is implicitly added to all roles by the compiler. # technically it is incorrect to skip it, but policy writers # and analysts don't expect to see it in results, and it # will confuse, especially for role set equality user queries. u.roles = frozenset(r for r in RoleEbitmapIterator.factory(policy, &symbol.roles.roles) if r != "object_r") if policy.mls: u._level = Level.factory(policy, &symbol.exp_dfltlevel) u._range = Range.factory(policy, &symbol.exp_range) return u @property def mls_level(self): """The user's default MLS level.""" if self._level: return self._level else: raise MLSDisabled @property def mls_range(self): """The user's MLS range.""" if self._range: return self._range else: raise MLSDisabled def statement(self): cdef: list roles = list(str(r) for r in self.roles) str stmt = "user {0} roles ".format(self.name) size_t count = len(roles) if count == 1: stmt += roles[0] else: stmt += "{{ {0} }}".format(' '.join(roles)) if self._level: stmt += " level {0.mls_level} range {0.mls_range};".format(self) else: stmt += ";" return stmt # # Iterator Classes # cdef class UserHashtabIterator(HashtabIterator): """Iterate over users in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.hashtab_t *table): """Factory function for creating User iterators.""" i = UserHashtabIterator() i.policy = policy i.table = table i.reset() return i def __next__(self): super().__next__() return User.factory(self.policy, self.curr.datum) cdef class UserEbitmapIterator(EbitmapIterator): """Iterate over a user ebitmap.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ebitmap_t *bmap): """Factory function for creating User ebitmap iterators.""" i = UserEbitmapIterator() i.policy = policy i.bmap = bmap i.reset() return i def __next__(self): super().__next__() return User.factory(self.policy, self.policy.user_value_to_datum(self.bit)) setools-4.4.0/setools/policyrep/util.pxi000066400000000000000000000144621402045477700204250ustar00rootroot00000000000000# Copyright 2016-2017, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # # # Classes # class PolicyEnum(enum.Enum): """ Base class for policy enumerations. Standard Enum behavior except for returning the enum name for the default string representation and basic string format. """ def __str__(self): return self.name def __format__(self, spec): if not spec: return self.name else: return super(PolicyEnum, self).__format__(spec) def __eq__(self, other): return super(PolicyEnum, self).__eq__(other) def __hash__(self): return hash(self.name) @classmethod def lookup(cls, value): """Look up an enumeration by name or value.""" try: return cls(value) except ValueError: return cls[value] class WeakKeyDefaultDict(weakref.WeakKeyDictionary): """ A dictionary with a weak-referenced key and a default value. This is a combination of WeakKeyDictionary and defaultdict classes and has the interfaces of both, with the exception of the constructor. WeakKeyDefaultDict(default_factory, [dict]) """ def __init__(self, default_factory, *args): self.default_factory = default_factory super().__init__(args) def __getitem__(self, key): try: return super().__getitem__(key) except KeyError: return self.__missing__(key) def __missing__(self, key): if self.default_factory is None: raise KeyError(key) defaultvalue = self.default_factory() self.__setitem__(key, defaultvalue) return defaultvalue # # Functions # cdef void sepol_logging_callback(void *varg, sepol.sepol_handle_t * sh, const char *fmt, ...): """Python logging for sepol log callback.""" cdef: va_list args char *msg va_start(args, fmt) if vasprintf(&msg, fmt, args) < 0: raise MemoryError va_end(args) logging.getLogger("libsepol").debug(msg) free(msg) cdef void ebitmap_set_bit(sepol.ebitmap_t * e, unsigned int bit, int value): """ Set a specific bit value in an ebitmap. This is derived from the libsepol function of the same name. """ cdef: sepol.ebitmap_node_t *n sepol.ebitmap_node_t *prev sepol.ebitmap_node_t *new uint32_t startbit = bit & ~(sepol.MAPSIZE - 1) uint32_t highbit = startbit + sepol.MAPSIZE if highbit == 0: raise LowLevelPolicyError("Bitmap overflow, bit {0:#06x}".format(bit)) prev = NULL n = e.node; while n and n.startbit <= bit: if (n.startbit + sepol.MAPSIZE) > bit: if value: n.map |= sepol.MAPBIT << (bit - n.startbit) else: n.map &= ~(sepol.MAPBIT << (bit - n.startbit)) if not n.map: # drop this node from the bitmap if not n.next: # this was the highest map # within the bitmap if prev: e.highbit = prev.startbit + sepol.MAPSIZE else: e.highbit = 0 if prev: prev.next = n.next else: e.node = n.next free(n) return prev = n n = n.next if not value: return new = calloc(1, sizeof(sepol.ebitmap_node_t)) if new == NULL: raise MemoryError new.startbit = startbit; new.map = sepol.MAPBIT << (bit - new.startbit) if not 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 cdef int hashtab_insert(sepol.hashtab_t h, sepol.hashtab_key_t key, sepol.hashtab_datum_t datum): """ Insert a node into a hash table. This is derived from the libsepol function of the same name. """ cdef: int hvalue sepol.hashtab_ptr_t prev, cur, newnode hvalue = h.hash_value(h, key) prev = NULL cur = h.htable[hvalue] while cur and h.keycmp(h, key, cur.key) > 0: prev = cur cur = cur.next if cur and h.keycmp(h, key, cur.key) == 0: raise LowLevelPolicyError("Error inserting into hash table. Key already exists.") newnode = calloc(1, sizeof(sepol.hashtab_node_t)) if newnode == NULL: raise MemoryError 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 += 1 cdef flatten_list(input_list): """ Flatten a list with nested lists. e.g. [A, B, [D, E], C] turns into: [A, B, D, E, C] """ cdef list ret = [] for i in input_list: if isinstance(i, list): ret.extend(flatten_list(i)) else: ret.append(i) return ret def lookup_boolean_name_sub(name): """ Read the /etc/selinux/TYPE/booleans.subs_dist file looking for a record with 'name'. Return the translated name if a corresponding substitution exists, otherwise return the original name. """ cdef: char *_name = selinux.selinux_boolean_sub(name) str new_name = name if _name == NULL: raise MemoryError # cast "char *" to "str" and free try: new_name = _name finally: free(_name) return new_name setools-4.4.0/setools/policyrep/xencontext.pxi000066400000000000000000000150031402045477700216370ustar00rootroot00000000000000# Copyright 2017-2018, Chris PeBenito # Derived from netcontext.py # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # IomemconRange = collections.namedtuple("IomemconRange", ["low", "high"]) IoportconRange = collections.namedtuple("IoportconRange", ["low", "high"]) # # Classes # cdef class Devicetreecon(Ocontext): """A devicetreecon statement.""" cdef readonly str path @staticmethod cdef inline Devicetreecon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Devicetreecon objects.""" cdef Devicetreecon d = Devicetreecon.__new__(Devicetreecon) d.policy = policy d.key = symbol d.path = intern(symbol.u.name) d.context = Context.factory(policy, symbol.context) return d def statement(self): return "devicetreecon {0.path} {0.context}".format(self) cdef class Iomemcon(Ocontext): """A iomemcon statement.""" cdef readonly object addr @staticmethod cdef inline Iomemcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Iomemcon objects.""" cdef Iomemcon i = Iomemcon.__new__(Iomemcon) i.policy = policy i.key = symbol i.addr = IomemconRange(symbol.u.iomem.low_iomem, symbol.u.iomem.high_iomem) i.context = Context.factory(policy, symbol.context) return i def statement(self): low, high = self.addr if low == high: return "iomemcon {0} {1}".format(low, self.context) else: return "iomemcon {0}-{1} {2}".format(low, high, self.context) cdef class Ioportcon(Ocontext): """A ioportcon statement.""" cdef readonly object ports @staticmethod cdef inline Ioportcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Ioportcon objects.""" cdef Ioportcon i = Ioportcon.__new__(Ioportcon) i.policy = policy i.key = symbol i.ports = IoportconRange(symbol.u.ioport.low_ioport, symbol.u.ioport.high_ioport) i.context = Context.factory(policy, symbol.context) return i def statement(self): low, high = self.ports if low == high: return "ioportcon {0} {1}".format(low, self.context) else: return "ioportcon {0}-{1} {2}".format(low, high, self.context) cdef class Pcidevicecon(Ocontext): """A pcidevicecon statement.""" cdef readonly object device @staticmethod cdef inline Pcidevicecon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Pcidevicecon objects.""" cdef Pcidevicecon p = Pcidevicecon.__new__(Pcidevicecon) p.policy = policy p.key = symbol p.device = symbol.u.device p.context = Context.factory(policy, symbol.context) return p def statement(self): return "pcidevicecon {0.device} {0.context}".format(self) cdef class Pirqcon(Ocontext): """A pirqcon statement.""" cdef readonly object irq @staticmethod cdef inline Pirqcon factory(SELinuxPolicy policy, sepol.ocontext_t *symbol): """Factory function for creating Pirqcon objects.""" cdef Pirqcon p = Pirqcon.__new__(Pirqcon) p.policy = policy p.key = symbol p.irq = symbol.u.pirq p.context = Context.factory(policy, symbol.context) return p def statement(self): return "pirqcon {0.irq} {0.context}".format(self) # # Iterators # cdef class DevicetreeconIterator(OcontextIterator): """Iterator for devicetreecon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Devicetreecon iterators.""" i = DevicetreeconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Devicetreecon.factory(self.policy, self.ocon) cdef class IomemconIterator(OcontextIterator): """Iterator for iomemcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Iomemcon iterators.""" i = IomemconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Iomemcon.factory(self.policy, self.ocon) cdef class IoportconIterator(OcontextIterator): """Iterator for ioportcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Ioportcon iterators.""" i = IoportconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Ioportcon.factory(self.policy, self.ocon) cdef class PcideviceconIterator(OcontextIterator): """Iterator for pcidevicecon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Pcidevicecon iterators.""" i = PcideviceconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Pcidevicecon.factory(self.policy, self.ocon) cdef class PirqconIterator(OcontextIterator): """Iterator for pirqcon statements in the policy.""" @staticmethod cdef factory(SELinuxPolicy policy, sepol.ocontext_t *head): """Factory function for creating Pirqcon iterators.""" i = PirqconIterator() i.policy = policy i.head = i.curr = head return i def __next__(self): super().__next__() return Pirqcon.factory(self.policy, self.ocon) setools-4.4.0/setools/portconquery.py000066400000000000000000000126261402045477700200440ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from socket import IPPROTO_TCP, IPPROTO_UDP from typing import Iterable, Optional, Tuple, Union from .mixins import MatchContext from .query import PolicyQuery from .policyrep import Portcon, PortconRange, PortconProtocol from .util import match_range class PortconQuery(MatchContext, PolicyQuery): """ Port context query. Parameter: policy The policy to query. Keyword Parameters/Class attributes: protocol The protocol to match (socket.IPPROTO_TCP for TCP or socket.IPPROTO_UDP for UDP) ports A 2-tuple of the port range to match. (Set both to the same value for a single port) ports_subset If true, the criteria will match if it is a subset of the portcon's range. ports_overlap If true, the criteria will match if it overlaps any of the portcon's range. ports_superset If true, the criteria will match if it is a superset of the portcon's range. ports_proper If true, use proper superset/subset operations. No effect if not using set operations. user The criteria to match the context's user. user_regex If true, regular expression matching will be used on the user. role The criteria to match the context's role. role_regex If true, regular expression matching will be used on the role. type_ The criteria to match the context's type. type_regex If true, regular expression matching will be used on the type. range_ The criteria to match the context's range. range_subset If true, the criteria will match if it is a subset of the context's range. range_overlap If true, the criteria will match if it overlaps any of the context's range. range_superset If true, the criteria will match if it is a superset of the context's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ _protocol: Optional[PortconProtocol] = None _ports: Optional[PortconRange] = None ports_subset: bool = False ports_overlap: bool = False ports_superset: bool = False ports_proper: bool = False @property def ports(self) -> Optional[PortconRange]: return self._ports @ports.setter def ports(self, value: Optional[Tuple[int, int]]) -> None: if value: pending_ports = PortconRange(*value) if all(pending_ports): if pending_ports.low < 1 or pending_ports.high < 1: raise ValueError("Port numbers must be positive: {0.low}-{0.high}". format(pending_ports)) if pending_ports.low > pending_ports.high: raise ValueError( "The low port must be smaller than the high port: {0.low}-{0.high}". format(pending_ports)) self._ports = pending_ports else: self._ports = None @property def protocol(self) -> Optional[PortconProtocol]: return self._protocol @protocol.setter def protocol(self, value: Optional[Union[str, PortconProtocol]]) -> None: if value: self._protocol = PortconProtocol.lookup(value) else: self._protocol = None def __init__(self, policy, **kwargs) -> None: super(PortconQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Portcon]: """Generator which yields all matching portcons.""" self.log.info("Generating portcon results from {0.policy}".format(self)) self.log.debug("Ports: {0.ports}, overlap: {0.ports_overlap}, " "subset: {0.ports_subset}, superset: {0.ports_superset}, " "proper: {0.ports_proper}".format(self)) self.log.debug("Protocol: {0.protocol!r}".format(self)) self._match_context_debug(self.log) for portcon in self.policy.portcons(): if self.ports and not match_range( portcon.ports, self.ports, self.ports_subset, self.ports_overlap, self.ports_superset, self.ports_proper): continue if self.protocol and self.protocol != portcon.protocol: continue if not self._match_context(portcon.context): continue yield portcon setools-4.4.0/setools/query.py000066400000000000000000000035611402045477700164350ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from abc import ABC, abstractmethod from logging import Logger from typing import Iterable from .policyrep import SELinuxPolicy class PolicyQuery(ABC): """Abstract base class for SELinux policy queries.""" log: Logger policy: SELinuxPolicy def __init__(self, policy: SELinuxPolicy, **kwargs) -> None: self.policy = policy # keys are sorted in reverse order so regex settings # are set before the criteria, e.g. name_regex # is set before name. This ensures correct behavior # since the criteria descriptors are sensitve to # regex settings. for name in sorted(kwargs.keys(), reverse=True): attr = getattr(self, name, None) # None is not callable if callable(attr): raise ValueError("Keyword parameter {0} conflicts with a callable.".format(name)) setattr(self, name, kwargs[name]) @abstractmethod def results(self) -> Iterable: """ Generator which returns the matches for the query. This method should be overridden by subclasses. """ pass setools-4.4.0/setools/rbacrulequery.py000066400000000000000000000137241402045477700201570ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import cast, Iterable, Optional, Pattern, Union from . import mixins, query from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .exception import InvalidType, RuleUseError from .policyrep import AnyRBACRule, RBACRuletype, Role, TypeOrAttr from .util import match_indirect_regex class RBACRuleQuery(mixins.MatchObjClass, query.PolicyQuery): """ Query the RBAC rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source role/attribute to match. source_indirect If true, members of an attribute will be matched rather than the attribute itself. source_regex If true, regular expression matching will be used on the source role/attribute. Obeys the source_indirect option. target The name of the target role/attribute to match. target_indirect If true, members of an attribute will be matched rather than the attribute itself. target_regex If true, regular expression matching will be used on the target role/attribute. Obeys target_indirect option. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. default The name of the default role to match. default_regex If true, regular expression matching will be used on the default role. """ ruletype = CriteriaSetDescriptor(enum_class=RBACRuletype) source = CriteriaDescriptor("source_regex", "lookup_role") source_regex: bool = False source_indirect: bool = True _target: Optional[Union[Pattern, Role, TypeOrAttr]] = None target_regex: bool = False target_indirect: bool = True tclass = CriteriaSetDescriptor("tclass_regex", "lookup_class") tclass_regex: bool = False default = CriteriaDescriptor("default_regex", "lookup_role") default_regex: bool = False @property def target(self) -> Optional[Union[Pattern, Role, TypeOrAttr]]: return self._target @target.setter def target(self, value: Optional[Union[str, Role, TypeOrAttr]]) -> None: if not value: self._target = None elif self.target_regex: self._target = re.compile(value) else: try: self._target = self.policy.lookup_type_or_attr(cast(Union[str, TypeOrAttr], value)) except InvalidType: self._target = self.policy.lookup_role(cast(Union[str, Role], value)) def __init__(self, policy, **kwargs) -> None: super(RBACRuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[AnyRBACRule]: """Generator which yields all matching RBAC rules.""" self.log.info("Generating RBAC rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) for rule in self.policy.rbacrules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source role # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type (role_transition)/role(allow) # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # try: if not self._match_object_class(rule): continue except RuleUseError: continue # # Matching on default role # if self.default: try: # because default role is always a single # role, hard-code indirect to True # so the criteria can be an attribute if not match_indirect_regex( rule.default, self.default, True, self.default_regex): continue except RuleUseError: continue # if we get here, we have matched all available criteria yield rule setools-4.4.0/setools/rolequery.py000066400000000000000000000051121402045477700173110ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .descriptors import CriteriaSetDescriptor from .mixins import MatchName from .policyrep import Role from .query import PolicyQuery from .util import match_regex_or_set class RoleQuery(MatchName, PolicyQuery): """ Query SELinux policy roles. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The role name to match. name_regex If true, regular expression matching will be used on the role names. types The type to match. types_equal If true, only roles with type sets that are equal to the criteria will match. Otherwise, any intersection will match. types_regex If true, regular expression matching will be used on the type names instead of set logic. """ types = CriteriaSetDescriptor("types_regex", "lookup_type") types_equal: bool = False types_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(RoleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Role]: """Generator which yields all matching roles.""" self.log.info("Generating role results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " "eq: {0.types_equal}".format(self)) for r in self.policy.roles(): if not self._match_name(r): continue if self.types and not match_regex_or_set( set(r.types()), self.types, self.types_equal, self.types_regex): continue yield r setools-4.4.0/setools/sensitivityquery.py000066400000000000000000000055331402045477700207510ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import Iterable from .descriptors import CriteriaDescriptor from .mixins import MatchAlias, MatchName from .policyrep import Sensitivity from .query import PolicyQuery from .util import match_level class SensitivityQuery(MatchAlias, MatchName, PolicyQuery): """ Query MLS Sensitivities Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The name of the category to match. name_regex If true, regular expression matching will be used for matching the name. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. sens The criteria to match the sensitivity by dominance. sens_dom If true, the criteria will match if it dominates the sensitivity. sens_domby If true, the criteria will match if it is dominated by the sensitivity. """ sens = CriteriaDescriptor(lookup_function="lookup_sensitivity") sens_dom: bool = False sens_domby: bool = False def __init__(self, policy, **kwargs) -> None: super(SensitivityQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Sensitivity]: """Generator which yields all matching sensitivities.""" self.log.info("Generating sensitivity results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) self.log.debug("Sens: {0.sens!r}, dom: {0.sens_dom}, domby: {0.sens_domby}".format(self)) for s in self.policy.sensitivities(): if not self._match_name(s): continue if not self._match_alias(s): continue if self.sens: if self.sens_dom: if self.sens < s: continue elif self.sens_domby: if self.sens > s: continue elif self.sens != s: continue yield s setools-4.4.0/setools/terulequery.py000066400000000000000000000225501402045477700176550ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from typing import cast, Iterable, Optional, Set, Tuple from . import mixins, query from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .exception import RuleUseError, RuleNotConditional from .policyrep import AnyTERule, AVRuleXperm, IoctlSet, TERuletype from .util import match_indirect_regex, match_regex_or_set class TERuleQuery(mixins.MatchObjClass, mixins.MatchPermission, query.PolicyQuery): """ Query the Type Enforcement rules. Parameter: policy The policy to query. Keyword Parameters/Class attributes: ruletype The list of rule type(s) to match. source The name of the source type/attribute to match. source_indirect If true, members of an attribute will be matched rather than the attribute itself. Default is true. source_regex If true, regular expression matching will be used on the source type/attribute. Obeys the source_indirect option. Default is false. target The name of the target type/attribute to match. target_indirect If true, members of an attribute will be matched rather than the attribute itself. Default is true. target_regex If true, regular expression matching will be used on the target type/attribute. Obeys target_indirect option. Default is false. tclass The object class(es) to match. tclass_regex If true, use a regular expression for matching the rule's object class. Default is false. perms The set of permission(s) to match. perms_equal If true, the permission set of the rule must exactly match the permissions criteria. If false, any set intersection will match. Default is false. perms_regex If true, regular expression matching will be used on the permission names instead of set logic. Default is false. perms_subset If true, the rule matches if the permissions criteria is a subset of the rule's permission set. Default is false. default The name of the default type to match. default_regex If true, regular expression matching will be used on the default type. Default is false. boolean The set of boolean(s) to match. boolean_regex If true, regular expression matching will be used on the booleans. Default is false. boolean_equal If true, the booleans in the conditional expression of the rule must exactly match the criteria. If false, any set intersection will match. Default is false. """ ruletype = CriteriaSetDescriptor(enum_class=TERuletype) source = CriteriaDescriptor("source_regex", "lookup_type_or_attr") source_regex: bool = False source_indirect: bool = True target = CriteriaDescriptor("target_regex", "lookup_type_or_attr") target_regex: bool = False target_indirect: bool = True default = CriteriaDescriptor("default_regex", "lookup_type_or_attr") default_regex: bool = False boolean = CriteriaSetDescriptor("boolean_regex", "lookup_boolean") boolean_regex: bool = False boolean_equal: bool = False _xperms: Optional[IoctlSet] = None xperms_equal: bool = False @property def xperms(self) -> Optional[IoctlSet]: return self._xperms @xperms.setter def xperms(self, value: Optional[Iterable[Tuple[int, int]]]) -> None: if value: pending_xperms: Set[int] = set() for low, high in value: if not (0 <= low <= 0xffff): raise ValueError("{0:#07x} is not a valid ioctl.".format(low)) if not (0 <= high <= 0xffff): raise ValueError("{0:#07x} is not a valid ioctl.".format(high)) if high < low: high, low = low, high pending_xperms.update(i for i in range(low, high + 1)) self._xperms = IoctlSet(pending_xperms) else: self._xperms = None def __init__(self, policy, **kwargs) -> None: super(TERuleQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[AnyTERule]: """Generator which yields all matching TE rules.""" self.log.info("Generating TE rule results from {0.policy}".format(self)) self.log.debug("Ruletypes: {0.ruletype}".format(self)) self.log.debug("Source: {0.source!r}, indirect: {0.source_indirect}, " "regex: {0.source_regex}".format(self)) self.log.debug("Target: {0.target!r}, indirect: {0.target_indirect}, " "regex: {0.target_regex}".format(self)) self._match_object_class_debug(self.log) self._match_perms_debug(self.log) self.log.debug("Xperms: {0.xperms!r}, eq: {0.xperms_equal}".format(self)) self.log.debug("Default: {0.default!r}, regex: {0.default_regex}".format(self)) self.log.debug("Boolean: {0.boolean!r}, eq: {0.boolean_equal}, " "regex: {0.boolean_regex}".format(self)) for rule in self.policy.terules(): # # Matching on rule type # if self.ruletype: if rule.ruletype not in self.ruletype: continue # # Matching on source type # if self.source and not match_indirect_regex( rule.source, self.source, self.source_indirect, self.source_regex): continue # # Matching on target type # if self.target and not match_indirect_regex( rule.target, self.target, self.target_indirect, self.target_regex): continue # # Matching on object class # if not self._match_object_class(rule): continue # # Matching on permission set # try: if self.perms and rule.extended: if self.perms_equal and len(self.perms) > 1: # if criteria is more than one standard permission, # extended perm rules can never match if the # permission set equality option is on. continue if cast(AVRuleXperm, rule).xperm_type not in self.perms: continue elif not self._match_perms(rule): continue except RuleUseError: continue # # Matching on extended permissions # try: if self.xperms and not match_regex_or_set( rule.perms, self.xperms, self.xperms_equal, False): continue except RuleUseError: continue # # Matching on default type # if self.default: try: # because default type is always a single # type, hard-code indirect to True # so the criteria can be an attribute if not match_indirect_regex( rule.default, self.default, True, self.default_regex): continue except RuleUseError: continue # # Match on Boolean in conditional expression # if self.boolean: try: if not match_regex_or_set( rule.conditional.booleans, self.boolean, self.boolean_equal, self.boolean_regex): continue except RuleNotConditional: continue # if we get here, we have matched all available criteria yield rule setools-4.4.0/setools/typeattrquery.py000066400000000000000000000053521402045477700202320ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .descriptors import CriteriaSetDescriptor from .mixins import MatchName from .policyrep import TypeAttribute from .query import PolicyQuery from .util import match_regex_or_set class TypeAttributeQuery(MatchName, PolicyQuery): """ Query SELinux policy type attributes. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The type name to match. name_regex If true, regular expression matching will be used on the type names. types The type to match. types_equal If true, only attributes with type sets that are equal to the criteria will match. Otherwise, any intersection will match. types_regex If true, regular expression matching will be used on the type names instead of set logic. """ types = CriteriaSetDescriptor("types_regex", "lookup_type") types_equal: bool = False types_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(TypeAttributeQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[TypeAttribute]: """Generator which yields all matching types.""" self.log.info("Generating type attribute results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Types: {0.types!r}, regex: {0.types_regex}, " "eq: {0.types_equal}".format(self)) for attr in self.policy.typeattributes(): if not self._match_name(attr): continue if self.types and not match_regex_or_set( set(attr.expand()), self.types, self.types_equal, self.types_regex): continue yield attr setools-4.4.0/setools/typequery.py000066400000000000000000000071121402045477700173330ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable, Optional from .descriptors import CriteriaSetDescriptor from .mixins import MatchAlias, MatchName from .policyrep import Type from .query import PolicyQuery from .util import match_regex_or_set class TypeQuery(MatchAlias, MatchName, PolicyQuery): """ Query SELinux policy types. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The type name to match. name_regex If true, regular expression matching will be used on the type names. alias The alias name to match. alias_regex If true, regular expression matching will be used on the alias names. attrs The attribute to match. attrs_equal If true, only types with attribute sets that are equal to the criteria will match. Otherwise, any intersection will match. attrs_regex If true, regular expression matching will be used on the attribute names instead of set logic. permissive The permissive state to match. If this is None, the state is not matched. """ attrs = CriteriaSetDescriptor("attrs_regex", "lookup_typeattr") attrs_regex: bool = False attrs_equal: bool = False _permissive: Optional[bool] = None @property def permissive(self) -> Optional[bool]: return self._permissive @permissive.setter def permissive(self, value) -> None: if value is None: self._permissive = None else: self._permissive = bool(value) def __init__(self, policy, **kwargs) -> None: super(TypeQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[Type]: """Generator which yields all matching types.""" self.log.info("Generating type results from {0.policy}".format(self)) self._match_name_debug(self.log) self._match_alias_debug(self.log) self.log.debug("Attrs: {0.attrs!r}, regex: {0.attrs_regex}, " "eq: {0.attrs_equal}".format(self)) self.log.debug("Permissive: {0.permissive}".format(self)) for t in self.policy.types(): if not self._match_name(t): continue if not self._match_alias(t): continue if self.attrs and not match_regex_or_set( set(t.attributes()), self.attrs, self.attrs_equal, self.attrs_regex): continue if self.permissive is not None and t.ispermissive != self.permissive: continue yield t setools-4.4.0/setools/userquery.py000066400000000000000000000114771402045477700173410ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import re from typing import Iterable from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor from .mixins import MatchName from .policyrep import User from .query import PolicyQuery from .util import match_regex_or_set, match_level, match_range class UserQuery(MatchName, PolicyQuery): """ Query SELinux policy users. Parameter: policy The policy to query. Keyword Parameters/Class attributes: name The user name to match. name_regex If true, regular expression matching will be used on the user names. roles The attribute to match. roles_equal If true, only types with role sets that are equal to the criteria will match. Otherwise, any intersection will match. roles_regex If true, regular expression matching will be used on the role names instead of set logic. level The criteria to match the user's default level. level_dom If true, the criteria will match if it dominates the user's default level. level_domby If true, the criteria will match if it is dominated by the user's default level. level_incomp If true, the criteria will match if it is incomparable to the user's default level. range_ The criteria to match the user's range. range_subset If true, the criteria will match if it is a subset of the user's range. range_overlap If true, the criteria will match if it overlaps any of the user's range. range_superset If true, the criteria will match if it is a superset of the user's range. range_proper If true, use proper superset/subset operations. No effect if not using set operations. """ level = CriteriaDescriptor(lookup_function="lookup_level") level_dom: bool = False level_domby: bool = False level_incomp: bool = False range_ = CriteriaDescriptor(lookup_function="lookup_range") range_overlap: bool = False range_subset: bool = False range_superset: bool = False range_proper: bool = False roles = CriteriaSetDescriptor("roles_regex", "lookup_role") roles_equal: bool = False roles_regex: bool = False def __init__(self, policy, **kwargs) -> None: super(UserQuery, self).__init__(policy, **kwargs) self.log = logging.getLogger(__name__) def results(self) -> Iterable[User]: """Generator which yields all matching users.""" self.log.info("Generating user results from {0.policy}".format(self)) self._match_name_debug(self.log) self.log.debug("Roles: {0.roles!r}, regex: {0.roles_regex}, " "eq: {0.roles_equal}".format(self)) self.log.debug("Level: {0.level!r}, dom: {0.level_dom}, domby: {0.level_domby}, " "incomp: {0.level_incomp}".format(self)) self.log.debug("Range: {0.range_!r}, subset: {0.range_subset}, overlap: {0.range_overlap}, " "superset: {0.range_superset}, proper: {0.range_proper}".format(self)) for user in self.policy.users(): if not self._match_name(user): continue if self.roles and not match_regex_or_set( user.roles, self.roles, self.roles_equal, self.roles_regex): continue if self.level and not match_level( user.mls_level, self.level, self.level_dom, self.level_domby, self.level_incomp): continue if self.range_ and not match_range( user.mls_range, self.range_, self.range_subset, self.range_overlap, self.range_superset, self.range_proper): continue yield user setools-4.4.0/setools/util.py000066400000000000000000000203321402045477700162400ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from contextlib import suppress from typing import Iterable, List, Optional, Tuple from .exception import InvalidPermission, NoCommon from .policyrep import Level, ObjClass, SELinuxPolicy def match_regex(obj, criteria, regex: bool) -> bool: """ Match the object with optional regular expression. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. """ if regex: return bool(criteria.search(str(obj))) else: return obj == criteria def match_set(obj, criteria, equal: bool) -> bool: """ Match the object (a set) with optional set equality. Parameters: obj The object to match. (a set) criteria The criteria to match. (a set) equal If set equality should be used. Otherwise any set intersection will match. """ if equal: return obj == criteria else: return bool(obj.intersection(criteria)) def match_in_set(obj, criteria, regex: bool) -> bool: """ Match if the criteria is in the list, with optional regular expression matching. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. """ if regex: return bool([m for m in obj if criteria.search(str(m))]) else: return criteria in obj def match_indirect_regex(obj, criteria, indirect: bool, regex: bool) -> bool: """ Match the object with optional regular expression and indirection. Parameters: obj The object to match. criteria The criteria to match. regex If regular expression matching should be used. indirect If object indirection should be used, e.g. expanding an attribute. """ if indirect: if regex: return bool([o for o in obj.expand() if criteria.search(str(o))]) else: return bool(set(criteria.expand()).intersection(obj.expand())) else: return match_regex(obj, criteria, regex) def match_regex_or_set(obj, criteria, equal: bool, regex: bool) -> bool: """ Match the object (a set) with either set comparisons (equality or intersection) or by regex matching of the set members. Regular expression matching will override the set equality option. Parameters: obj The object to match. (a set) criteria The criteria to match. equal If set equality should be used. Otherwise any set intersection will match. Ignored if regular expression matching is used. regex If regular expression matching should be used. """ if regex: return bool([m for m in obj if criteria.search(str(m))]) else: return match_set(obj, set(criteria), equal) def match_range(obj, criteria, subset: bool, overlap: bool, superset: bool, proper: bool) -> bool: """ Match ranges of objects. obj An object with attributes named "low" and "high", representing the range. criteria An object with attributes named "low" and "high", representing the criteria. subset If true, the criteria will match if it is a subset obj's range. overlap If true, the criteria will match if it overlaps any of the obj's range. superset If true, the criteria will match if it is a superset of the obj's range. proper If true, use proper superset/subset operations. No effect if not using set operations. """ if overlap: return ((obj.low <= criteria.low <= obj.high) or ( obj.low <= criteria.high <= obj.high) or ( criteria.low <= obj.low and obj.high <= criteria.high)) elif subset: if proper: return ((obj.low < criteria.low and criteria.high <= obj.high) or ( obj.low <= criteria.low and criteria.high < obj.high)) else: return obj.low <= criteria.low and criteria.high <= obj.high elif superset: if proper: return ((criteria.low < obj.low and obj.high <= criteria.high) or ( criteria.low <= obj.low and obj.high < criteria.high)) else: return (criteria.low <= obj.low and obj.high <= criteria.high) else: return criteria.low == obj.low and obj.high == criteria.high def match_level(obj: Level, criteria: Level, dom: bool, domby: bool, incomp: bool) -> bool: """ Match the an MLS level. obj The level to match. criteria The criteria to match. (a level) dom If true, the criteria will match if it dominates obj. domby If true, the criteria will match if it is dominated by obj. incomp If true, the criteria will match if it is incomparable to obj. """ if dom: return (criteria >= obj) elif domby: return (criteria <= obj) elif incomp: return (criteria ^ obj) else: return (criteria == obj) def validate_perms_any(perms: Iterable[str], tclass: Optional[Iterable[ObjClass]] = None, policy: Optional[SELinuxPolicy] = None) -> None: """ Validate that each permission is valid for at least one of specified object classes. If no classes are specified, then all classes in the policy are checked. A tclass or policy must be specified. Parameters: perms A container of str permission names. Keyword Parameters. tclass An iterable of 1 or more ObjClass. policy A SELinuxPolicy Exceptions: ValueError Invalid parameter. InvalidPermission One or more permissions is invalid. Return: None """ if not perms: raise ValueError("No permissions specified.") if tclass: # make local mutable set selected_classes = set(c for c in tclass) elif policy: selected_classes = set(policy.classes()) else: raise ValueError("No object class(es) or policy specified.") invalid = set(p for p in perms) for c in selected_classes: invalid -= c.perms with suppress(NoCommon): invalid -= c.common.perms if not invalid: break else: if tclass: raise InvalidPermission( "Permission(s) do not exist in the specified classes: {}" .format(", ".join(invalid))) else: raise InvalidPermission( "Permission(s) do not exist any class: {}" .format(", ".join(invalid))) def xperm_str_to_tuple_ranges(perms: str, separator: str = ",") -> List[Tuple[int, int]]: """ Create a extended permission list of ranges from a string representation of ranges. This does not do any checking for out-of-range values. Parameters: perms A string representation of integer extended permissions, such as "0x08,0x30-0x40,0x55,0x60-0x65" Keyword Parameters: separator The separator between permissions/permission ranges. Default is "," Return: List[Tuple[int, int]] equivalent of the permissions. """ xperms: List[Tuple[int, int]] = [] for item in perms.split(separator): rng = item.split("-") if len(rng) == 2: xperms.append((int(rng[0], base=16), int(rng[1], base=16))) elif len(rng) == 1: xperms.append((int(rng[0], base=16), int(rng[0], base=16))) else: raise ValueError("Unable to parse \"{}\" for xperms.".format(item)) return xperms setools-4.4.0/setoolsgui/000077500000000000000000000000001402045477700154165ustar00rootroot00000000000000setools-4.4.0/setoolsgui/__init__.py000066400000000000000000000015301402045477700175260ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .apol import ApolMainWindow from . import widget import logging logging.getLogger(__name__).addHandler(logging.NullHandler()) setools-4.4.0/setoolsgui/apol/000077500000000000000000000000001402045477700163515ustar00rootroot00000000000000setools-4.4.0/setoolsgui/apol/__init__.py000066400000000000000000000035301402045477700204630ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from .mainwindow import ApolMainWindow # Analysis tabs: from .boolquery import BoolQueryTab from .boundsquery import BoundsQueryTab from .categoryquery import CategoryQueryTab from .commonquery import CommonQueryTab from .constraintquery import ConstraintQueryTab from .defaultquery import DefaultQueryTab from .dta import DomainTransitionAnalysisTab from .fsusequery import FSUseQueryTab from .genfsconquery import GenfsconQueryTab from .ibendportconquery import IbendportconQueryTab from .ibpkeyconquery import IbpkeyconQueryTab from .infoflow import InfoFlowAnalysisTab from .initsidquery import InitialSIDQueryTab from .mlsrulequery import MLSRuleQueryTab from .netifconquery import NetifconQueryTab from .nodeconquery import NodeconQueryTab from .objclassquery import ObjClassQueryTab from .portconquery import PortconQueryTab from .rbacrulequery import RBACRuleQueryTab from .rolequery import RoleQueryTab from .sensitivityquery import SensitivityQueryTab from .summary import SummaryTab from .terulequery import TERuleQueryTab from .typeattrquery import TypeAttributeQueryTab from .typequery import TypeQueryTab from .userquery import UserQueryTab setools-4.4.0/setoolsgui/apol/analysistab.py000066400000000000000000000102751402045477700212420ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from typing import Dict, NamedTuple from enum import Enum import sip from PyQt5.QtWidgets import QDialogButtonBox, QScrollArea from ..widget import SEToolsWidget class AnalysisSection(Enum): """Groupings of analysis tabs""" Analysis = 1 Components = 2 General = 3 Labeling = 4 Other = 5 Rules = 6 TAB_REGISTRY: Dict[str, type] = {} class TabRegistry(sip.wrappertype): """ Analysis tab registry metaclass. This registers tabs to be used both for populating the content of the "choose analysis" dialog and also for saving tab/workspace info. """ def __new__(cls, clsname, superclasses, attributedict): classdef = super().__new__(cls, clsname, superclasses, attributedict) if clsname != "AnalysisTab": assert "section" in attributedict, "Class {} is missing the section value, " \ "this is an setools bug".format(clsname) assert "tab_title" in attributedict, "Class {} is missing the tab_title value, " \ "this is an setools bug".format(clsname) assert "mlsonly" in attributedict, "Class {} is missing the mlsonly value, " \ "this is an setools bug".format(clsname) # ensure there is no duplication of class name or title for existing_tabname, existing_class in TAB_REGISTRY.items(): if existing_tabname == clsname: raise TypeError("Analysis tab {} conflicts with registered tab {}, " "this is an setools bug".format(clsname, existing_tabname)) if existing_class.tab_title == attributedict["tab_title"]: raise TypeError("Analysis tab {}'s title \"{}\" conflicts with registered tab " "{}, this is an setools bug.". format(clsname, attributedict["tab_title"], existing_tabname)) TAB_REGISTRY[clsname] = classdef return classdef # pylint: disable=invalid-metaclass class AnalysisTab(SEToolsWidget, QScrollArea, metaclass=TabRegistry): """Base class for Apol analysis tabs.""" # A QButtonBox which has an Apply button # for running the analysis. buttonBox = None # The set of tab fields that are in error errors = None # Normal and error palettes to use orig_palette = None error_palette = None # # Tab error state # def set_criteria_error(self, field, error): """Set the specified widget to an error state.""" field.setToolTip("Error: {0}".format(error)) field.setPalette(self.error_palette) self.errors.add(field) self._check_query() def clear_criteria_error(self, field, tooltip): """Clear the specified widget's error state.""" field.setToolTip(tooltip) field.setPalette(self.orig_palette) self.errors.discard(field) self._check_query() def _check_query(self): button = self.buttonBox.button(QDialogButtonBox.Apply) enabled = not self.errors button.setEnabled(enabled) button.setToolTip("Run the analysis." if enabled else "There are errors in the tab.") # # Save/Load tab # def save(self): raise NotImplementedError def load(self, settings): raise NotImplementedError # # Results runner # def run(self, button): raise NotImplementedError def update_complete(self, count): raise NotImplementedError setools-4.4.0/setoolsgui/apol/apol.qch000066400000000000000000002600001402045477700177770ustar00rootroot00000000000000SQLite format 3@ !!.á –«A ž 9 ¿ B » 6 Î X Ú d ¿fU#'oindexFileIdIndexFileNameTableCREATE INDEX FileIdIndex ON FileNameTable(FileId)W''oindexFileNameIndexFileNameTableCREATE INDEX FileNameIndex ON FileNameTable(Name)I!aindexNameIndexIndexTableCREATE INDEX NameIndex ON IndexTable(Name)X''qtableMetaDataTableMetaDataTableCREATE TABLE MetaDataTable(Name Text, Value BLOB )t##/tableFolderTableFolderTableCREATE TABLE FolderTable(Id INTEGER PRIMARY KEY, Name Text, NamespaceID INTEGER )| ''7tableFileNameTableFileNameTableCREATE TABLE FileNameTable (FolderId INTEGER, Name TEXT, FileId INTEGER, Title TEXT )t ++tableFileFilterTableFileFilterTable CREATE TABLE FileFilterTable (FilterAttributeId INTEGER, FileId INTEGER )f '' tableFileDataTableFileDataTable CREATE TABLE FileDataTable (Id INTEGER PRIMARY KEY, Data BLOB ) 77#tableFileAttributeSetTableFileAttributeSetTable CREATE TABLE FileAttributeSetTable (Id INTEGER, FilterAttributeId INTEGER ) 33/tableContentsFilterTableContentsFilterTable CREATE TABLE ContentsFilterTable (FilterAttributeId INTEGER, ContentsId INTEGER ){''5tableContentsTableContentsTable CREATE TABLE ContentsTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Data BLOB )x--#tableIndexFilterTableIndexFilterTableCREATE TABLE IndexFilterTable (FilterAttributeId INTEGER, IndexId INTEGER )c))tableIndexItemTableIndexItemTableCREATE TABLE IndexItemTable (Id INTEGER, IndexId INTEGER ) !!‚ tableIndexTableIndexTableCREATE TABLE IndexTable (Id INTEGER PRIMARY KEY, Name TEXT, Identifier TEXT, NamespaceId INTEGER, FileId INTEGER, Anchor TEXT )h##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )h)) tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY,Name TEXT ) ÚÚ$Ocom.github.selinuxproject.setools ÷÷apol ÷÷Apol ûû „óϽ£„) Permission Mappermmap- Information Flow infoflow"A Domain Transition Analysis  DTA  ãûõïéã     TTƒ) †Tindex.htmlApolanalyses.htmlAnalysesinfoflow.html2Information Flow Analysisdta.html4Domain Transition Analysiscomponents.htmlComponentsrules.html Ruleslabeling.htmlLabeling ûû ûû ûûÄå‡\<nxœuU]oã6|ׯئM4®­j HsÀ Àî ¤µÅE$eGýõ%;AqO–©]îìÌìªþi¹¤ç§ }¢ëö†î~½ývãiÇmoq‡iAOO+¢{c(ÇFB‡#w+Z.7Ut2¼¹÷ÎÔëò\Õým> íã“¶ã½:£Û‰î­2SÔ±^# BØÝæåˆ»4Ÿpt'G~³ëu¤½6L­³Ii©QQ·Ô³ñ¤íÞ…A%í,á‰Æ¨íŠ-HÑ!(ßëV™Ê—Šj®HÉŽ$l¹ƒN=Ú^Ù–;ºžQÞPNÒÑï®ç*çøàŽºcÜÐ3©FÉMî÷zí¯3h×èMõø¦myA‘Uh{ ±¨2*1Í`Z7xgÙ‚Ãë4yŽ ’ŸJ¥t3&9pÍ?Ü&jŠñÃÏaÐ1¢kœgäÕâ¢ÒV'­L¤í·¿púü´ýPhA–ÓÉ…ïNfú&2¹ü†ˆJÞ4h••7÷ 8Œ(´ª×Ò_îò•ƒÐOÑ cLJ€Á3Ënæp©Z3v"rN*H\W†â‘©C®¶”ªê,g¹E2Â'¡;‹ÌxêµP/†ÉN‹£÷.€ÙèÆÐr¹£ÑV…郬ÄQÙ/´g•F˜™5U 騃vô>‹=ÚŽƒ™¤™Î!Úºô^­x¢Œ°ÌW*† ¼Ay¡n¶rNã#‰sžSÈŽC*èÔ³CQ«&O'Øø~À¿t{6¥( Žf[ž–1Áâò-Á¸vcœ›¨â„©zÞoéÂÚÿœHd¿Ñí—|ÏèWÅóynŸÙޱ -@ý AëfóâÙÖëfCûà† ‡_aº|8 “CQ˜Õ£2úÝi«êÅš‰àÙó¬(KФĢJzà?òÿ<ð >;U†µâh‰«Pz¯CL¸CÂ[ã"Ö<³²c2´×óTѳòÊÀp1¯‹¹à‚¸ƒKñÇ%ª£\[+êïÿ¼³ŠIW}ÌÏ2¬ƒòW›ËÔÂcÞ#”©ÍªB}0¦ËçSvä/ñ7^m~8 ù¾¹/ˆ±M*¤Lý¸m‹J;:zž´ …À(Òí÷LœåËõ„µ”àîê¾0{¨£ÒFåórMͼ| °\ðÀ¶5²¾œ-Y©Ï·'Õ”4¡Y¾2öÃÊž-¥%4@[ÙªÄ ó’`Õöç ‚¬Z¡Å]tÝ9O6Þ<Õûªy¯áË^ËÁRþÒ :ð%Xea÷åi΄ç¬Š„ÁÊòB$âŠ4ÿ0ž9Ž7œr7xœÅX]oÛ6}ç¯àžjN²fÀRÃ@–¥C€¢CŸ Z¢c®’¨‘TaØß¹üdËùZ[¬A-‘—çÞ{šÿptÄ/tÝu»q|’Mù靿K#mkùRf›Jú¶ñwï.Ž9?/ î×ZŽ%ÒÜÉü˜-ØÜ)WÈůºªÂ~QYå”®øy%ŠÖ*;? +Ø|óúÑex͛׋sþE¶|-…kŒäzÍ—m-ùeµÖ&“¥¬€wy9åVfQ®åÊr·‘\¬TA?f¹\«Jò<œæ°Ýò­r¾Ý¨lÃk£o(áJSÍxc%ö 7\NF2]9£ .²LZ¡¹^ý)3D`Ì …Õ~G>qQåÜ:£2W´ZŒsFÜ$Nž†°þ±‘Ï•ÍkUu;Î@Œ‡Ñ§ŒLµ^ãIåX¤¡äeƒ¼Âi«ü3gÞøS¨Å͇×—|ùé÷˳À‚Èî!9…µ:SÂwÈGâó<¦¦%˜=Å&=Ôé>ßéð " ñp–ç׿].Ÿ€ƒí¡ è…Õ ª4¼PÔÙak²ÿöê]p–O.ß/¯?ýþáê}8nÚŸ'ðºbò=À‰U!ùZáO(ÐP͵“æVº,8ƒ| )9C1Õ¸Xdn‚ÆÒZ'KžÁB‚zBù ¤·° t!i”èérµ[‰[J ½‚¥G‡¢“¡©Í~Ì3ËE€4?ñ?B‡éÞYéÀ¢îí1[Â×L—%VdÂRüŸ<Š>©¯’Ÿƒ‚ Õ—qÞ컺Fîc·¥€†1!Ì(YñK|iO™¯ƒ• ™ Åß×ú“È}—Ä(b©?ûs©x+YL µwoÚ·lÎ%ž—4â¹Ãv×7ÒåІÇRu@T?¥Ø²µN­ò*ô-y/ÊÎÂMß·Àᦔ1â@f>»ñTXƒú™±°®Æ®m>Z9`u ÆÎjJçh‹/pß´¬Öª ›“Ï:¶ sŸŸÐ¥ä½²ãzŠMjØÂÙ}DâÁ)9À/tª,Vl†YV‘ýØuvFâ[mXŒf˜4òl^Â8þy|<Ä”§ñ³~ÜvØÞÀÙÚXJéÈ#šA!ÕH%Q…Lù¶µ×Ð&7Ýu쌂@ƒ©T½ûir0ËÓØz¾6%¡Eʽ|D¾ýojþâP¾!ÞžcC%ŠœÃGáœáÿgzù "ÿ¨‹=å{Æï…|§T^÷1U¨îÈç‡ÞÀ`Q#y&ï;ÂLGæeÜM£»tÌ9Í¿a2–~vCƒFi×1vçʨÛ[ñ4&ÚZÑ0o™KŠ"ج e7Aú ÆNT^“,¯Ïßß\-¯>¼‡¬‡ð »Ç1•G÷n˜ríóÖ°Z´$(õ§Ø'3dk™©uUÄÆ-iÓC%Ö…e"Ýx‚w„ù‘YŠyr-š"¦ ÏX%·d ;HŠt‰S§Ô^ïz]À+ÿ•Ìð2E/LHP4¿女ì/i!¡Qd‰-f­¿""•pêNíŒ v@ûT´£ùÞ6žî9i%„°,ÖXÙ²ÕÀ¦Þ_>ð7Tã3r¿Óý }š!Ú(Ü]–½äé~‡PÂ9Àˆl{>„ÜGRƒ(YéH€ †‡÷£Ø“n`OÙy‡µކs0"ßăHšöX¼›;vÀe6ŒöhRŠÈC¬…'ðŒ>'ÿÿÚ…‚"„Hìxœe‘ÁNÃ0 †ï} sim(ªT*n•Xy€,óÚ 4I:Ö·Çí8$Òÿù·ýKWy ¹Ùë~ˆp­nàîv{Ç0èP – õóÚ¶)jc`õ` ú Èó*QGƒUC£#‹6Q^H&†í/Ì2®êGF«ÔO¢ÜpžNú€Ù2¢´Œ ð,Gmq¥Wä=dŒ£"é$:²vO­¶ÓùkS!JWeËöš„É9òì}ŸÐÏÚöë #C‹úïaí“áÏèê‘È,ñDÉb% §éÉkL#¥¦îJäóþ U„ÆÈR¾CtÔ'~)îf÷WB£×û)¦…W¾Î·,—ÄŸ8¨¨ºUƒ.&xœmAjÃ0E÷>ÅoV-ÔvÓEE˜”B Ë\@$²50ÖIiñí3M²h¡›?¼7Ÿ1m‹­¤%Ó*Ox}Y¿á}Y þ¢°LË3öûm ̸²ŠøüåOÚÖ6¦Reo‡èx)¾˜þ–Ö¿–“ì„QÎ)IÖC5xŒÂ,ß'¸;ünú¤ð™u0Yã²7+Š£ŒÊv¡Î¼²;yv•$âS׸•‘–9kz5ÿê§êîæ‡ÌŽ¢¾êb¡«ÿÚÿô_G±b± ÖúôîèâÜÖ        ùÜ»‘{M0 !rules.htmlRules 'labeling.htmlLabeling, '?infoflow.htmlInformation Flow Analysis !index.htmlApol( Adta.htmlDomain Transition Analysis +!components.htmlComponents 'analyses.htmlAnalyses ÷÷ doc ÊîÊ"%3CreationDate2012-12-20T12:00:00!qchVersion1.0¡ÙAâ|{–Ì?dŸÿ'Êçß?"Ä[m7¬ $(6¸©à}9¯È#U鑯ölݸF®úÊ(Pz™àhˆK†!þ²3O:)T³Ë¿Ø‘)ÑÁηRù3¤H ÙÅ€/†œäÁŸ¥È© 13±mï•ÈÞÂô´Ô=„ž|>IäöÁ6O\¶¨^¨\/¶î©¬jú*˜SŽÒ5Óˆ¿,ù7“Þª+vÇq-ФqÚ­ôšöGB`Wì;âöü±ò“oé½F‹aŽ~hêèÜRZÅR’¤ïuã-×¢Éê6åÓÎÞ˧#y³[ýßìÒkÃOÿÃܾ¦oé³Hµ†t/l°•';Qé ÈÜÛ¥z!ã‰B/ëRød6•ŽÿòÊ[ýþó§óZ•W䯩$׫‚ñ1f±RQˆ’²V;ÛHµ•ÂO²e³¯ÄᢰTc[¯¥4>/%J»çti–Ž¥ìM{žàïÌŠ¯(e"ÛÑ•4W¹'OZ¿Fñ¥/”ìŒRTP?†ÜŠj¥È@%ÏN©uö/}_+bObˆ¢›˜™E5%5ø²I¿ÍË`A¨½T¬,¨ýï±ìÌrûU.º#ÉUÌâô¡Zû1RBáaYΣ«rs®Í&œ$ *¿mÝï–4ÔžH¥ú„ŒEäXX?P\PÚ¶dLäÈ'Å h9yKö6•Ø"uqTfM®ˆ°¤D#ºö¨ ²7~o“ÀÇòÂ+\hä,zÓmmÿ‡•`=Ça™âË™&~Nsp˜ºHPÎl…ðË€ŒÆ‹õŽ|­ !F_F1I(AJÚïŒ'æ‘ñ:¡*º™ˆ_¨ìÈœàP´Iß9n(ÙO>•Ø™|O?Dê‚Tç˜/-S2’ƒ¹µi™êVTÒEÖu`ú‹þ°÷ÌJB+Ê>Ïj†r%fâÖ‚ÃxÏ”ü¢éÒ6kŠTP&ì³<§ÿÙy5&êÿüFæ{Õ÷TÒãQØ"1p’;8 *tBd™ÌÑR²`¿ÔW¾|ÃvàR=BµLÌ$rìä\•’ΊJ¬Ó6±qkð$ì!5–ó×pΑa^¾Š‹MŠ»•¤»Êº'Îí°–é,SÌ7S Ü[2íi™q˜Ñ­ÙÛ|ÁöæðâÈìÓ—r>ˆX`$vwcîTd+&›Æ,´À–‹âsq@BŽUçֹߥ„²píB‘,H5 ”’jÊ‚5°èýBruLÊ+v§y°©-Wc­‹0!›ûBÖȯCV‘fŒâp#’†¥ŒXˆ…ÏÔí×¶Kʽìdj/ )ÉÇJYÍ%®Š¬2E, ÷s‰ß+±{XN8¿ç ËKâË/þ·wonõçwoþ™BåÃOBWÏÿýúùÃû[ýé—YW|Š…¼â9i‹ˆäwëûŸ>Ñ«»›õ=ENtSèe+Åš“ioE¾.Ѐ;Æøe™Ïàì¹×LZKÁªˆ¯\ƒfåM_¤AwzÈ2Åv’ŠÃ©7 ZÎíî›v%£Ë°‹G<âkJjÈ9Lý9ÆïPÆï£üó^©!-;ÆòŒxç‚«Šø®=‰9oÛÅôØ*¹Xf´iQ"!GjmÑýS¦‰à7åK-¨˜\¸r¥f®”árUK§íÒ£¡¸”'êÑûLÑûW;*sÒ.UÔƒ®PNlÙ¯˜0 ÈÇéÅ>k1©ü¥ÖoS›¯è÷R–qX%Oï8' 5)¥U»ˆ¾î*_Û{rmÓ÷ÝÝ ÿVæé¤>Énb®éØSc¼É´qêddk*Œ@­e„°i‘Ã=/ÏåKõ©ÅTBEB¹š;i.tbQ€ò–Å”¥óÍ“äâ§ôtË@sÇÕqëZ¶øÆÚFš¾·ŸþýÝç‡oÅÌê|Ë)€%ÇìL»¹†±¢Â$Ô4Ñ®“.{×q·¾½î;bZ¦TA ±‚ùåËUñ5£TòB ²X~OúÉt§ôªÃ¬aÖUÅ“f†Q+¦IõÎÍO*ø. Š'W–ÊŽÄ¥df JËaB¯⸆ÇYÒÞÔVæ«ð×è1糨³%,ƒÌ^@ åpQºšäŽL²ø@&ºøLº™ÄiwMÄÁ 0µX"æyÂ}o÷‡> Ó[lÜ× Ñ„#ö'.ÖÚ4„År8úƒ…òHý‹¼1ŽÕ7çdÙ&9wâ U5ª;Ó _A‚ðè<9Jè¦á½É'ucÖ¶áâÇŸ£,ÒÉñbhEY/¤b!:yºƒ€u,Ö‰{ÿB§ ÖßBë9GÆô,8Fj™lŸWŒ“µQYqXº‚'2ËžkNAR,Ê%Óì0û ³§hÝ j®È=ýArw*æjmÑêÑèý"ˆIÉf¿I7䨩(•YKß!0üöž²ÿéÒådòçñõ¯•›È 26éÑEñ÷ n}æÉ«äÊ+å8æCÌêøP&ÌDÆ)ã‘„€ÙW¬¬Wß½T¬×+¡Œ{xöM‡ZTÀ=•5dañ÷óÁ,Zì×YLÈÊ‚‡ŠB;u¬BóˆdÔÚëmgØ=jj®(Õ÷ì>‰Ïqs½&GW³äœë·HØ…~˜,íŠÝK_ïAÃê"—jhéÒR5aŽT2±«Om¦¤\> Ÿ$áKdúVS‰˜!öQ­b·1t¦:a3Ex˜j×wKlŽ®]¯¬s<öšáÞ ˆÎUïaWLy…nL'!À'Žb š^/¶..$=õ&ðŠPô–£ÉgNÆ61}$9@¾”ŠhÍÀ™ÕѧÉj‹[Š›ã´@úVi=UÉ•¶œ‹Á²X=è„ÇÏ+hÍŽs:Öý8$ç“!Ì]S¿x¹"L€ú Æ^ÆÖý9²®Ò•–0¿Ó"îu-æS`G ãiÖ7(GŒ 1‹¥ÿßÊ\À(NüèÙ£"ÆßÀÄU¸è$ÈC͉PùòÈsWnÒ Mïû,€ªœb—L‹Ýe z{ȃ7‚¡®Í§D ¥¦‡¬ÌKF•C<¾œz›z®ã*ñÆ,ptd>¸­f±so•M ”\U¡J Ä‹/FsMN<»ÌÙ¯/ÍÅ­‰œ¶=ƒ2t`o{=[Gý¯Í+ãB>#-}oJ—%éL¶’L$Ę \³RL{Ч2+h½D]q’èl¤‹~‡Tÿ¯J±+ŒÜþöVâÀÿìynÒÉ ¨BfjN‘íÔ—N!‡ê¢ ¹ÆÄÚY¦»V,¤Jûâ¬Áæ‰`Ÿòm‘±øùI‡ª 8„ÎÔ¢Úeu<¼ÍQaäì(>ž _šrÑ÷×í8oÖÄä;8bK0,½æõe' z»Š¯esàR*Œ|ƒm9 “4yà’d¸edê©rï^Ì‚šœ·Ñà qZÀvã͇tÖ  /H"Æ+¹ÑUX–ÕîGôšXR´w?–çã™F¾X“kIlTç§ÖÄ ~ŠP”Y3÷óŒìU‘–r#øüÁâJΨ½|ÎZžboàfÞi¸øü+öO†~öµ]Þ¾E,±µ£ž}0Ͱ˜ßkê¬ÁM¨R—¿½0¾0 ß°Ú®.̓ZÛ<|>Åñê¶L;x€+#Ú‹cà=Îy’ï&òË™ˆql@¢rcðêr“EnÒåS~¼GT¼h|ÉàÀõiÐ~á¶WÙÌoZý9¶0b¾`u¾¿'Ó Ì_íxQ3NPô–>¸ÇÑ5:zñÍ©ªGh8ð é.PÖnï§®wó¬„O9¹ËE’VÏx}ŠŠ×Â)_ݘtH±£Ró¯Æckâ[Á›!t¸gÚÙ‚ö˜ÜÜà³ßöàW,eúÃu @nj€MÁ:‘œÜ&ùÖqåÔx,a‹dšFFDAq`%×!ÀÅ… ¼Wºµ£x¥‰6ß&:¤Ür>XÑ–²\ò@úo:ÀQó=ˆ"9 ȃgÉ 2Å>zzí®<»Ê;Ë€ƒïòÁcã„,ûÎ5j©„&oŸoæð}.\%BW<ÊAB²]ç»krØ·Áôƒ‘Sn¸ËBæM ¥°«í0måB’­ðŽvÔϘ"ø5Yíõj§âþÞs!ZŒƒãìôŠ/jË/ËXÕ¸*ºbOæÓ³‰à"è8 ãJ\›Q?ÆÅW¾rì› #¼ó!£*S],¤bV2 ÆÛ‚>‚ìÏÊwâBS2zëMsq¨Æ”‘8ó±î!ÅóÀx7;}DK[/5ÌjLPÉ4_ÙÒ³ÙVJÛD¹¡OJºÈ_% Îi¶Ã¸­ÝÉü»Tü9/æÙ:•óRßîl>K®‘‚‹Ä{'G„ÜmpÅÎÀâý¬U9ËTé^¥í¡Û\l.ŒN/uG—»ƒ’ˆ¯þ¶Óuqý– ÕéÆåÝÆx ˜Ž úÑœB¼(—á¾ÕI²xªhInóA_’(¾<{&,¾¤ /ƒ¥àwr½¼=]è}ÏÌ®3vì²L‹úÝ^wñÏ .à@B»JÆþi>Ý;¹‰·skq0Z,3ÐÄ!drC)ÖE"ºÇ@?Ք̃ѣ¿Àhê6$f¢[ùt¿¤ögüMÇ-Ë:éjÿÀð„ÃàÔO]æÛ­é6æžBÛá2Ù„jà»Ú‚Dò‡#ÄE†ð£ü½Édd¤§ü¨3vJ®…UŠN7nïd.!ñ·ýx—?_^‰á1‘ÉL¿“Ã5"þw˜düR ªð7D|I!ÃK/³Ìó†l¼x|œ¹—Y;àŽ˜N­ì¥R•ýÈ"}–Wc‘õ‡>çÚÐûÃt'9Ž%Vg›Ä+ÕÎÆv¹‹‰X»:ݶt“û.7/ìmÿ "*Xù åû# þÄå‡\<nxœuU]oã6|ׯئM4®­j HsÀ Àî ¤µÅE$eGýõ%;AqO–©]îìÌìªþi¹¤ç§ }¢ëö†î~½ývãiÇmoq‡iAOO+¢{c(ÇFB‡#w+Z.7Ut2¼¹÷ÎÔëò\Õým> íã“¶ã½:£Û‰î­2SÔ±^# BØÝæåˆ»4Ÿpt'G~³ëu¤½6L­³Ii©QQ·Ô³ñ¤íÞ…A%í,á‰Æ¨íŠ-HÑ!(ßëV™Ê—Šj®HÉŽ$l¹ƒN=Ú^Ù–;ºžQÞPNÒÑï®ç*çøàŽºcÜÐ3©FÉMî÷zí¯3h×èMõø¦myA‘Uh{ ±¨2*1Í`Z7xgÙ‚Ãë4yŽ ’ŸJ¥t3&9pÍ?Ü&jŠñÃÏaÐ1¢kœgäÕâ¢ÒV'­L¤í·¿púü´ýPhA–ÓÉ…ïNfú&2¹ü†ˆJÞ4h••7÷ 8Œ(´ª×Ò_îò•ƒÐOÑ cLJ€Á3Ënæp©Z3v"rN*H\W†â‘©C®¶”ªê,g¹E2Â'¡;‹ÌxêµP/†ÉN‹£÷.€ÙèÆÐr¹£ÑV…郬ÄQÙ/´g•F˜™5U 騃vô>‹=ÚŽƒ™¤™Î!Úºô^­x¢Œ°ÌW*† ¼Ay¡n¶rNã#‰sžSÈŽC*èÔ³CQ«&O'Øø~À¿t{6¥( Žf[ž–1Áâò-Á¸vcœ›¨â„©zÞoéÂÚÿœHd¿Ñí—|ÏèWÅóynŸÙޱ -@ý AëfóâÙÖëfCûà† ‡_aº|8 “CQ˜Õ£2úÝi«êÅš‰àÙó¬(KФĢJzà?òÿ<ð >;U†µâh‰«Pz¯CL¸CÂ[ã"Ö<³²c2´×óTѳòÊÀp1¯‹¹à‚¸ƒKñÇ%ª£\[+êïÿ¼³ŠIW}ÌÏ2¬ƒòW›ËÔÂcÞ#”©ÍªB}0¦ËçSvä/ñ7^m~8 ù¾¹/ˆ±M*¤Lý¸m‹J;:zž´ …À(Òí÷LœåËõ„µ”àîê¾0{¨£ÒFåórMͼ| °\ðÀ¶5²¾œ-Y©Ï·'Õ”4¡Y¾2öÃÊž-¥%4@[ÙªÄ ó’`Õöç ‚¬Z¡Å]tÝ9O6Þ<Õûªy¯áË^ËÁRþÒ :ð%Xea÷åi΄ç¬Š„ÁÊòB$âŠ4ÿ0ž9Ž7œr7xœÅX]oÛ6}ç¯àžjN²fÀRÃ@–¥C€¢CŸ Z¢c®’¨‘TaØß¹üdËùZ[¬A-‘—çÞ{šÿptÄ/tÝu»q|’Mù靿K#mkùRf›Jú¶ñwï.Ž9?/ î×ZŽ%ÒÜÉü˜-ØÜ)WÈůºªÂ~QYå”®øy%ŠÖ*;? +Ø|óúÑex͛׋sþE¶|-…kŒäzÍ—m-ùeµÖ&“¥¬€wy9åVfQ®åÊr·‘\¬TA?f¹\«Jò<œæ°Ýò­r¾Ý¨lÃk£o(áJSÍxc%ö 7\NF2]9£ .²LZ¡¹^ý)3D`Ì …Õ~G>qQåÜ:£2W´ZŒsFÜ$Nž†°þ±‘Ï•ÍkUu;Î@Œ‡Ñ§ŒLµ^ãIåX¤¡äeƒ¼Âi«ü3gÞøS¨Å͇×—|ùé÷˳À‚Èî!9…µ:SÂwÈGâó<¦¦%˜=Å&=Ôé>ßéð " ñp–ç׿].Ÿ€ƒí¡ è…Õ ª4¼PÔÙak²ÿöê]p–O.ß/¯?ýþáê}8nÚŸ'ðºbò=À‰U!ùZáO(ÐP͵“æVº,8ƒ| )9C1Õ¸Xdn‚ÆÒZ'KžÁB‚zBù ¤·° t!i”èérµ[‰[J ½‚¥G‡¢“¡©Í~Ì3ËE€4?ñ?B‡éÞYéÀ¢îí1[Â×L—%VdÂRüŸ<Š>©¯’Ÿƒ‚ Õ—qÞ컺Fîc·¥€†1!Ì(YñK|iO™¯ƒ• ™ Åß×ú“È}—Ä(b©?ûs©x+YL µwoÚ·lÎ%ž—4â¹Ãv×7ÒåІÇRu@T?¥Ø²µN­ò*ô-y/ÊÎÂMß·Àᦔ1â@f>»ñTXƒú™±°®Æ®m>Z9`u ÆÎjJçh‹/pß´¬Öª ›“Ï:¶ sŸŸÐ¥ä½²ãzŠMjØÂÙ}DâÁ)9À/tª,Vl†YV‘ýØuvFâ[mXŒf˜4òl^Â8þy|<Ä”§ñ³~ÜvØÞÀÙÚXJéÈ#šA!ÕH%Q…Lù¶µ×Ð&7Ýu쌂@ƒ©T½ûir0ËÓØz¾6%¡Eʽ|D¾ýojþâP¾!ÞžcC%ŠœÃGáœáÿgzù "ÿ¨‹=å{Æï…|§T^÷1U¨îÈç‡ÞÀ`Q#y&ï;ÂLGæeÜM£»tÌ9Í¿a2–~vCƒFi×1vçʨÛ[ñ4&ÚZÑ0o™KŠ"ج e7Aú ÆNT^“,¯Ïßß\-¯>¼‡¬‡ð »Ç1•G÷n˜ríóÖ°Z´$(õ§Ø'3dk™©uUÄÆ-iÓC%Ö…e"Ýx‚w„ù‘YŠyr-š"¦ ÏX%·d ;HŠt‰S§Ô^ïz]À+ÿ•Ìð2E/LHP4¿女ì/i!¡Qd‰-f­¿""•pêNíŒ v@ûT´£ùÞ6žî9i%„°,ÖXÙ²ÕÀ¦Þ_>ð7Tã3r¿Óý }š!Ú(Ü]–½äé~‡PÂ9Àˆl{>„ÜGRƒ(YéH€ †‡÷£Ø“n`OÙy‡µކs0"ßăHšöX¼›;vÀe6ŒöhRŠÈC¬…'ðŒ>'ÿÿÚ…‚"„Hìxœe‘ÁNÃ0 †ï} sim(ªT*n•Xy€,óÚ 4I:Ö·Çí8$Òÿù·ýKWy ¹Ùë~ˆp­nàîv{Ç0èP – õóÚ¶)jc`õ` ú Èó*QGƒUC£#‹6Q^H&†í/Ì2®êGF«ÔO¢ÜpžNú€Ù2¢´Œ ð,Gmq¥Wä=dŒ£"é$:²vO­¶ÓùkS!JWeËöš„É9òì}ŸÐÏÚöë #C‹úïaí“áÏèê‘È,ñDÉb% §éÉkL#¥¦îJäóþ U„ÆÈR¾CtÔ'~)îf÷WB£×û)¦…W¾Î·,—ÄŸ8¨¨ºUƒ.&xœmAjÃ0E÷>ÅoV-ÔvÓEE˜”B Ë\@$²50ÖIiñí3M²h¡›?¼7Ÿ1m‹­¤%Ó*Ox}Y¿á}Y þ¢°LË3öûm ̸²ŠøüåOÚÖ6¦Reo‡èx)¾˜þ–Ö¿–“ì„QÎ)IÖC5xŒÂ,ß'¸;ünú¤ð™u0Yã²7+Š£ŒÊv¡Î¼²;yv•$âS׸•‘–9kz5ÿê§êîæ‡ÌŽ¢¾êb¡«ÿÚÿô_G±b±  ² } ž ²iƒV3xœMPÁnÂ0 ½÷+¼[‘ ;ì0E•ºŠ[¹”þ ¦d’,N@ùû&´],?û=ûÙúE)è}(ÑÎK‚Ú¬àm³}‡)"† Íâ<ù¹¼Â0ôk€Ž\¡`¼âi Jµ•N6¶c&dÝü‚J/ÛgE²J‡¶ ž€s>ʈX7CZΞÈßî(ŠR Ⱥ ¢Ë$lÛ{Ç)­K2Qð£¸Ï”¬"¼"ÁMŽ6¨÷ÃaõÇ=¡ú:2ž 3™åh—¢x©ÇÏ®ÿÇœd-ìÜÙGƒtò“i÷l7w?:e\ƒ<oxœuAkÂ@…ïùÓ›Jc´‡ÊE‚ô.iœ$ ãκ3±äßwÕRzˆ—7ß{ó’¦°dßÛ´ £j o³ù;J/pÀªuLÜô¯PË)À‚î^hÁpÅÓÒ4OŒZ%Ì‹ò ɺÆd˜vþoEb|¾ðL ÷bÑ¥ÃÐG Ú"ÔLÄß7E¿)-ÏèT>LæcAGqÍ×rìØÿ9L÷w¸AWKÅnnU[ì·«A¾Cµõ³ðŽOøŒ}ÆYv;úé}½¦xÍt6}xœµ[ßs9r~Ç_ø…be­7ÙKJV”ò9vâ”w½ek³©Ô8’ˆ†Þ`F47•ÿ=ýuÌòmâºÚ“f0þÝ_7 »¿¹¾ÖoýáÔ¹í®×WÕRÿÝ«?é‡Î†Sжڵ¾ñÛÓJüøö¥ÖošFóÚ i‰ížlýR__ß«»Þõ½ÿÐn|·7½ó­~ßø£~Óšæ\¸»‘ên÷ê[«è­º;Ü¿9øF‡ápðmÕï¬6k׸þ¤{¯ÍÐ{úÚòó`MWí4ÔþÉv½v#qµ!âA¯m´¶ÕýÑëþt°y OCwðÁj¿!J.h¹Ðô?ÚÆÕ¶íÝæ¤†¶¶ÁufÝÐÚN­ýz°Uok-ôéûbSmzJ/×'môí§Þáme÷DO_=¼[j’ÎU'bã=ѳ_ÍþÐØ•v{³u-Ä2=ËfuØ™Úë8 Ám[¢Mì±ðüNèùÑwÄ#ol_ÝÈêum{ÛíA™XS‰0ËxÜ9R^É}eZKo:¿/6ù­v®ìËíJ¹¶v}ÐnIb ª9˜~ض­ºÓ JœñfkKªtmµzÒusÒ5¶^®tMfÕ/òÆ/FcO% \À[O³öôž=xM2’:{$òÚ ³I4Ž´˜=F ÑȰmzÓÖPN4h¶`á8-ýì»GþºÛ˜Š¼èîæp¯à­¥?³£'µúË»®¾b¿jG”m»…Ú §`ÉcM£:k‚oy@[5CM¯o¿úOãîá®ï¢ßè=Å¥i]؃¨ýÚwäZ¤ÌMc¿Â+ í²õ¾Vpm’Dz14íêè³@Îì6ÎÖ+M:%AI¶`:¼"†Æâ¶ÇΑì H ’üÄ™°Ysð*ÛÖqƒÊÃ4_Wúèú]r”V :?b ¿¨nh,B°Ö;²IgkYG]é½y„4®×µÛl\54=‹f¢F”°†m[èŸLÉQä²1 n“Eª¡ëH¨ e¤ýÃwÚ¯ÿ‹"\W ùï9[*¾> ¬H(¶5IIJ„Ô~ìpO‡ˆe2]§ÊTæ&ñ—Cà)¨ç˜÷•3ˆ&ÙV1WIž¸œ.BŽ`<:ç4·Î?Q6ƒ,ᓳGÄÕªB¦%AÀAPgœ$OŽÎNéûûû_ ¥ùÚŲ¥ infoflow)Permission Map-Information FlowADomain Transition Analysis DTA ‡üêÖɺ¨–‡!rules.html'labeling.html'infoflow.html!index.html dta.html+components.html'analyses.html ÒüöðêäÞØÒ setools-4.4.0/setoolsgui/apol/apol.qhc000066400000000000000000001000001402045477700177700ustar00rootroot00000000000000SQLite format 3@ .á ² †’$ º  we'' tableSettingsTableSettingsTableCREATE TABLE SettingsTable (Key TEXT PRIMARY KEY, Value BLOB )9M'indexsqlite_autoindex_SettingsTable_1SettingsTableh##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )u##1tableFolderTableFolderTableCREATE TABLE FolderTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Name TEXT )x))+tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY, Name TEXT, FilePath TEXT ) ÑÑ-Ocom.github.selinuxproject.setoolsapol.qch ÷÷ doc ÷÷apol ÷÷Apol ûû qÔ»n"èÉ´¡Œq 9FullTextSearchFallback %CreationTime[é©» ) HideAddressBar- EnableAddressBarA EnableDocumentationManager; HideFilterFunctionality? EnableFilterFunctionalityJ)LastShownPagesqthelp://com.github.selinuxproject.setools/doc/index.htmlK+defaultHomepageqthelp://com.github.selinuxproject.setools/doc/index.html#WindowTitleApol Help*-;LastRegisterTime2018-11-12T11:26:35.974 #G\—4{ìµÜÈ9FullTextSearchFallback %CreationTime )HideAddressBar -EnableAddressBarAEnableDocumentationManager;HideFilterFunctionality?EnableFilterFunctionality)LastShownPages+defaultHomepage#WindowTitle- LastRegisterTimesetools-4.4.0/setoolsgui/apol/apol.ui000066400000000000000000000205751402045477700176540ustar00rootroot00000000000000 ApolMainWindow_ui 0 0 800 600 640 480 apol 0 0 0 0 true QTabWidget::North -1 true true 0 0 800 19 &File &Help &Edit Permission &Map Workspace toolBar TopToolBarArea false &Open Policy Open an SELinux Policy Ctrl+O E&xit Ctrl+Q About Apol New Analysis Start a new analysis on this policy. Ctrl+N Cut Ctrl+X Copy Ctrl+C Paste Ctrl+V Open Permission Map Open permission map used for information flow analysis &Rename Tab Rename the active tab. &Close Tab Close the active tab. Ctrl+W Close Policy Close the current policy. Closes all analyses too. Edit Permission Map Save Permission Map Apol Help Save Tab Settings Save the current tab's settings to file. Ctrl+S Load Tab Settings Load settings for the current tab. Ctrl+L Load Workspace Load workspace from file. Ctrl+Shift+L Save Workspace Save workspace to file. Ctrl+Shift+S New Analysis From Settings Start a new analysis using settings from a file. Ctrl+Shift+N exit_apol triggered() ApolMainWindow_ui close() -1 -1 399 299 setools-4.4.0/setoolsgui/apol/boolquery.py000066400000000000000000000165541402045477700207570ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import BoolQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..boolmodel import BooleanTableModel, boolean_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class BoolQueryTab(AnalysisTab): """Bool browser and query tab.""" section = AnalysisSection.Components tab_title = "Booleans" mlsonly = False def __init__(self, parent, policy, perm_map): super(BoolQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = BoolQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.boolquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/boolquery.ui") # populate bool list self.bool_model = SEToolsListModel(self) self.bool_model.item_list = sorted(r for r in self.policy.bools()) self.bools.setModel(self.bool_model) # set up results self.table_results_model = BooleanTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.boolquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.bools.doubleClicked.connect(self.get_detail) self.bools.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Booleans browser # def get_detail(self): # .ui is set for single item selection. index = self.bools.selectedIndexes()[0] item = self.bool_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) boolean_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the Boolean name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Boolean name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_any", "default_true", "default_false", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_any", "default_true", "default_false", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. if self.default_any.isChecked(): self.query.default = None else: self.query.default = self.default_true.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} Boolean(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/boolquery.ui000066400000000000000000000341171402045477700207370ustar00rootroot00000000000000 BoolQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Booleans 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Boolean Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Boolean Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the user's name. Regex 120 0 Default State Any true True False QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander bools name name_regex default_any default_true default_false results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/boundsquery.py000066400000000000000000000167621402045477700213170ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import BoundsQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..boundsmodel import BoundsTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class BoundsQueryTab(AnalysisTab): """Bounds browser and query tab.""" section = AnalysisSection.Other tab_title = "Bounds" mlsonly = False def __init__(self, parent, policy, perm_map): super(BoundsQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = BoundsQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.boundsquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/boundsquery.ui") # set up results self.table_results_model = BoundsTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.parent.palette() self.error_palette = self.parent.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_parent_error() self.clear_child_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.boundsquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.parent.textEdited.connect(self.clear_parent_error) self.parent.editingFinished.connect(self.set_parent) self.parent_regex.toggled.connect(self.set_parent_regex) self.child.textEdited.connect(self.clear_child_error) self.child.editingFinished.connect(self.set_child) self.child_regex.toggled.connect(self.set_child_regex) self.buttonBox.clicked.connect(self.run) # # Parent criteria # def clear_parent_error(self): self.clear_criteria_error(self.parent, "Match the parent type.") def set_parent(self): try: self.query.parent = self.parent.text() except Exception as ex: self.log.error("Type parent error: {0}".format(ex)) self.set_criteria_error(self.parent, ex) def set_parent_regex(self, state): self.log.debug("Setting parent_regex {0}".format(state)) self.query.parent_regex = state self.clear_parent_error() self.set_parent() # # Child criteria # def clear_child_error(self): self.clear_criteria_error(self.child, "Match the child type.") def set_child(self): try: self.query.child = self.child.text() except Exception as ex: self.log.error("Type child error: {0}".format(ex)) self.set_criteria_error(self.child, ex) def set_child_regex(self, state): self.log.debug("Setting child_regex {0}".format(state)) self.query.child_regex = state self.clear_child_error() self.set_child() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "typebounds", "parent_regex", "child_regex"]) save_lineedits(self, settings, ["parent", "child"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "typebounds", "parent_regex", "child_regex"]) load_lineedits(self, settings, ["parent", "child"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.parent_regex = self.parent_regex.isChecked() self.query.child_regex = self.child_regex.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} bound(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/boundsquery.ui000066400000000000000000000420741402045477700212770ustar00rootroot00000000000000 BoundsQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Bounds Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 Clear false Qt::Horizontal 40 20 Select All false typebounds true 16777215 100 Parent (Bounding) Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 true Use regular expressions to match the context's role. Regex 16777215 100 Child (Bounded) Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the context's type. Regex QDialogButtonBox::Apply SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander typebounds clear_ruletypes all_ruletypes parent parent_regex child child_regex results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776
setools-4.4.0/setoolsgui/apol/categoryquery.py000066400000000000000000000165421402045477700216360ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import CategoryQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsmodel import MLSComponentTableModel, category_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class CategoryQueryTab(AnalysisTab): """Category browser and query tab.""" section = AnalysisSection.Components tab_title = "MLS Categories" mlsonly = True def __init__(self, parent, policy, perm_map): super(CategoryQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = CategoryQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.categoryquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/categoryquery.ui") # populate category list self.category_model = SEToolsListModel(self) self.category_model.item_list = sorted(self.policy.categories()) self.cats.setModel(self.category_model) # set up results self.table_results_model = MLSComponentTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.categoryquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.cats.doubleClicked.connect(self.get_detail) self.cats.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Category browser # def get_detail(self): # .ui is set for single item selection. index = self.cats.selectedIndexes()[0] item = self.category_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) category_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the category name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Category name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} categories found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/categoryquery.ui000066400000000000000000000312731402045477700216210ustar00rootroot00000000000000 CategoryQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Categories 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Categories Browser 0 0 16777215 16777215 Search Criteria QDialogButtonBox::Apply 16777215 120 Category Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander cats name name_regex results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/choose_analysis.ui000066400000000000000000000050571402045477700221020ustar00rootroot00000000000000 ChooseAnalysis 0 0 400 421 New Analysis Choose a new analysis to start: QAbstractItemView::SingleSelection true true 1 false Analyses Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox rejected() ChooseAnalysis reject() 316 260 286 274 buttonBox accepted() ChooseAnalysis accept() 199 400 199 210 analysisTypes itemDoubleClicked(QTreeWidgetItem*,int) ChooseAnalysis accept() 199 206 199 210 setools-4.4.0/setoolsgui/apol/chooseanalysis.py000066400000000000000000000054571402045477700217620ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from collections import defaultdict from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QDialog, QTreeWidgetItem from ..widget import SEToolsWidget from .analysistab import AnalysisSection, AnalysisTab, TAB_REGISTRY class ChooseAnalysis(SEToolsWidget, QDialog): """ Dialog for choosing a new analysis The below class attributes are used for populating the GUI contents and mapping them to the appropriate tab widget class for the analysis. """ def __init__(self, parent): super(ChooseAnalysis, self).__init__(parent) self.parent = parent # populate the analysis choices tree: self.analysis_choices = defaultdict(dict) for clsobj in TAB_REGISTRY.values(): self.analysis_choices[clsobj.section.name][clsobj.tab_title] = clsobj self.setupUi() def setupUi(self): self.load_ui("apol/choose_analysis.ui") def show(self, mls): self.analysisTypes.clear() for groupname, group in self.analysis_choices.items(): groupitem = QTreeWidgetItem(self.analysisTypes) groupitem.setText(0, groupname) groupitem._tab_class = None for entryname, cls in group.items(): if cls.mlsonly and not mls: continue item = QTreeWidgetItem(groupitem) item.setText(0, entryname) item._tab_class = cls groupitem.addChild(item) self.analysisTypes.expandAll() self.analysisTypes.sortByColumn(0, Qt.AscendingOrder) super(ChooseAnalysis, self).show() def accept(self, item=None): try: if not item: # .ui is set for single item selection. item = self.analysisTypes.selectedItems()[0] title = item.text(0) self.parent.create_new_analysis(title, item._tab_class) except (IndexError, TypeError): # IndexError: nothing is selected # TypeError: one of the group items was selected. pass else: super(ChooseAnalysis, self).accept() setools-4.4.0/setoolsgui/apol/commonquery.py000066400000000000000000000205621402045477700213060ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import CommonQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..commonmodel import CommonTableModel, common_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class CommonQueryTab(AnalysisTab): """Common browser and query tab.""" section = AnalysisSection.Components tab_title = "Common Permission Sets" mlsonly = False def __init__(self, parent, policy, perm_map): super(CommonQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = CommonQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.commonquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/commonquery.ui") # populate commons list self.common_model = SEToolsListModel(self) self.common_model.item_list = sorted(c for c in self.policy.commons()) self.commons.setModel(self.common_model) # populate perm list self.perms_model = SEToolsListModel(self) perms = set() for com in self.policy.commons(): perms.update(com.perms) self.perms_model.item_list = sorted(perms) self.perms.setModel(self.perms_model) # set up results self.table_results_model = CommonTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.commonquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.commons.doubleClicked.connect(self.get_detail) self.commons.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.buttonBox.clicked.connect(self.run) # # Class browser # def get_detail(self): # .ui is set for single item selection. index = self.commons.selectedIndexes()[0] item = self.common_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) common_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the common name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Common name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.perms_equal = self.perms_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} common(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/commonquery.ui000066400000000000000000000403241402045477700212710ustar00rootroot00000000000000 CommonQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Common Permission Sets 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Common Browser 0 0 16777215 16777215 Search Criteria Permission Set 0 0 250 16777215 A matching common will have the selected permissions. QAbstractItemView::ExtendedSelection Clear A matching common will a permission set equal to the selected permissions. Equal Qt::Horizontal 40 20 Invert Qt::Vertical 20 40 QDialogButtonBox::Apply 16777215 120 Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander commons name name_regex perms clear_perms invert_perms perms_equal results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226 clear_perms clicked() perms clearSelection() 592 216 442 276
setools-4.4.0/setoolsgui/apol/config.py000066400000000000000000000043331402045477700201730ustar00rootroot00000000000000# Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import logging import configparser import threading # # Configfile constants # APOLCONFIG = "~/.config/setools/apol.conf" HELP_SECTION = "Help" HELP_PGM = "assistant" DEFAULT_HELP_PGM = ("/usr/bin/assistant") class ApolConfig: """Apol configuration file.""" def __init__(self): self.log = logging.getLogger(__name__) self._lock = threading.Lock() self.path = os.path.expanduser(APOLCONFIG) self._config = configparser.ConfigParser() save = False if not self._config.read((self.path,)): save = True if not self._config.has_section(HELP_SECTION): self._config.add_section(HELP_SECTION) self._config.set(HELP_SECTION, HELP_PGM, DEFAULT_HELP_PGM) save = True if save: self.save() def save(self): """Save configuration file.""" with self._lock: try: os.makedirs(os.path.dirname(self.path), mode=0o755, exist_ok=True) with open(self.path, "w") as fd: self._config.write(fd) except Exception as ex: self.log.critical("Failed to save configuration file \"{0}\"".format(self.path)) @property def assistant(self): with self._lock: return self._config.get(HELP_SECTION, HELP_PGM, fallback=DEFAULT_HELP_PGM) @assistant.setter def assistant(self, value): with self._lock: self._config.set(HELP_SECTION, HELP_PGM, value) setools-4.4.0/setoolsgui/apol/constraintquery.py000066400000000000000000000317071402045477700222050ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import ConstraintQuery from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..constraintmodel import ConstraintTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class ConstraintQueryTab(AnalysisTab): """A constraint query.""" section = AnalysisSection.Rules tab_title = "Constraints" mlsonly = False def __init__(self, parent, policy, perm_map): super(ConstraintQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = ConstraintQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.constraintquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/constraintquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # setup indications of errors self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_user_error() self.clear_type_error() self.clear_role_error() # set up results self.table_results_model = ConstraintTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.constraintquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_user_regex(self.user_regex.isChecked()) self.set_role_regex(self.role_regex.isChecked()) self.set_type_regex(self.type_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # MLS constraints available only if policy is MLS if not self.policy.mls: self.mlsconstrain.setEnabled(False) self.mlsvalidatetrans.setEnabled(False) self.mlsconstrain.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) # # Ruletype criteria # def _set_ruletypes(self, value): self.constrain.setChecked(value) self.validatetrans.setChecked(value) if self.policy.mls: self.mlsconstrain.setChecked(value) self.mlsvalidatetrans.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes self.perms_model.set_classes(selected_classes) def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match constraints that have a user in the expression.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("User error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match constraints that have a role in the expression.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match constraints that have a type in the expression.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain", "mlsconstrain", "validatetrans", "mlsvalidatetrans", "user_regex", "role_regex", "type_regex", "perms_subset"]) save_lineedits(self, settings, ["user", "role", "type_"]) save_listviews(self, settings, ["tclass", "perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "constrain", "mlsconstrain", "validatetrans", "mlsvalidatetrans", "user_regex", "role_regex", "type_regex", "perms_subset"]) load_lineedits(self, settings, ["user", "role", "type_"]) load_listviews(self, settings, ["tclass", "perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.constrain, self.mlsconstrain, self.validatetrans, self.mlsvalidatetrans]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.perms_subset = self.perms_subset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} constraint(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions or expression column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(2) > 400: header.resizeSection(2, 400) if header.sectionSize(3) > 400: header.resizeSection(3, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/constraintquery.ui000066400000000000000000000640621402045477700221720ustar00rootroot00000000000000 ConstraintQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Constraint Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 MLSValidatetrans MLSConstrain Qt::Horizontal 40 20 Select All Constrain true Clear false Validatetrans false 16777215 100 Role In Expression 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 true Use regular expressions to match the context's role. Regex QDialogButtonBox::Apply Object Class 0 0 250 16777215 Match the object class of the constraint. QAbstractItemView::ExtendedSelection Clear Qt::Horizontal 40 20 Qt::Vertical 20 40 Invert 16777215 100 Type In Expression 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the context's type. Regex Permission Set 6 6 6 6 3 Invert Clear Qt::Horizontal 40 20 A matching rule will have all of the selected permissions. Match All Qt::Vertical 20 40 0 0 250 16777215 The list of permissions common to selected object classes. QAbstractItemView::ExtendedSelection User In Expression 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 133 20 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander constrain mlsconstrain validatetrans mlsvalidatetrans clear_ruletypes all_ruletypes role type_ clear_class invert_class perms clear_perms invert_perms perms_subset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 clear_perms clicked() perms clearSelection() 565 312 448 330 clear_class clicked() tclass clearSelection() 282 230 132 254
setools-4.4.0/setoolsgui/apol/defaultquery.py000066400000000000000000000176051402045477700214460ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import DefaultQuery, DefaultValue, DefaultRangeValue from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..defaultmodel import DefaultTableModel from .analysistab import AnalysisSection, AnalysisTab from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_comboboxes, load_listviews, load_textedits, \ save_checkboxes, save_comboboxes, save_listviews, save_textedits class DefaultQueryTab(AnalysisTab): """Default browser and query tab.""" section = AnalysisSection.Other tab_title = "Defaults" mlsonly = False def __init__(self, parent, policy, perm_map): super(DefaultQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = DefaultQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.defaultquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/defaultquery.ui") # set up results self.table_results_model = DefaultTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # these two lists have empty string as their first item # (in the .ui file): # populate default value list for i, e in enumerate(DefaultValue, start=1): self.default_value.insertItem(i, e.name, e) # populate default range value list for i, e in enumerate(DefaultRangeValue, start=1): self.default_range_value.insertItem(i, e.name, e) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.defaultquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.default_range_value.setEnabled(self.default_range.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.default_range.toggled.connect(self.default_range_value.setEnabled) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.buttonBox.clicked.connect(self.run) # # Ruletype criteria # def _set_ruletypes(self, value): self.default_user.setChecked(value) self.default_role.setChecked(value) self.default_type.setChecked(value) self.default_range.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_user", "default_role", "default_type", "default_range"]) save_comboboxes(self, settings, ["default_value", "default_range_value"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "default_user", "default_role", "default_type", "default_range"]) load_comboboxes(self, settings, ["default_value", "default_range_value"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.default_user, self.default_role, self.default_type, self.default_range]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.default = self.default_value.currentData(Qt.UserRole) if self.default_range_value.isEnabled(): self.query.default_range = self.default_range_value.currentData(Qt.UserRole) else: self.query.default_range = None # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} default(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/defaultquery.ui000066400000000000000000000444451402045477700214350ustar00rootroot00000000000000 DefaultQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 770 842 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Default Query Qt::Horizontal 40 20 0 1 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 0 Show: 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 0 0 16777215 150 Rule Type 6 6 6 6 3 Clear false Qt::Horizontal 40 20 Select All true default_user true default_role true default_type true default_range true QDialogButtonBox::Apply Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection 16777215 100 Default 6 6 6 6 3 0 0 0 0 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander default_user default_type default_role default_range clear_ruletypes all_ruletypes tclass clear_class invert_class default_value default_range_value results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 clear_class clicked() tclass clearSelection() 318 164 150 188
setools-4.4.0/setoolsgui/apol/dta.py000066400000000000000000000464511402045477700175050ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import pyqtSignal, Qt, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog, \ QTreeWidgetItem from setools import DomainTransitionAnalysis from ..logtosignal import LogHandlerToSignal from .analysistab import AnalysisSection, AnalysisTab from .excludetypes import ExcludeTypes from .exception import TabFieldError from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \ save_checkboxes, save_spinboxes, save_lineedits, save_textedits class DomainTransitionAnalysisTab(AnalysisTab): """A domain transition analysis tab.""" section = AnalysisSection.Analysis tab_title = "Domain Transition Analysis" mlsonly = False def __init__(self, parent, policy, perm_map): super(DomainTransitionAnalysisTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = DomainTransitionAnalysis(policy) self.query.source = None self.query.target = None self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.dta").removeHandler(self.handler) def setupUi(self): self.log.debug("Initializing UI.") self.load_ui("apol/dta.ui") # set up source/target autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.source.setCompleter(self.type_completion) self.target.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() # set up processing thread self.thread = ResultsUpdater(self.query) self.thread.raw_line.connect(self.raw_results.appendPlainText) self.thread.finished.connect(self.update_complete) self.thread.trans.connect(self.reset_browser) # set up browser thread self.browser_thread = BrowserUpdater(self.query) self.browser_thread.trans.connect(self.add_browser_children) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.setCancelButton(None) self.busy.reset() # update busy dialog from DTA INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.dta").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.max_path_length.setEnabled(self.all_paths.isChecked()) self.source.setEnabled(not self.flows_in.isChecked()) self.target.setEnabled(not self.flows_out.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) self.browser_tab.setEnabled(self.flows_in.isChecked() or self.flows_out.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.all_paths.toggled.connect(self.all_paths_toggled) self.flows_in.toggled.connect(self.flows_in_toggled) self.flows_out.toggled.connect(self.flows_out_toggled) self.reverse.stateChanged.connect(self.reverse_toggled) self.exclude_types.clicked.connect(self.choose_excluded_types) self.browser.currentItemChanged.connect(self.browser_item_selected) # # Analysis mode # def all_paths_toggled(self, value): self.clear_source_error() self.clear_target_error() self.max_path_length.setEnabled(value) def flows_in_toggled(self, value): self.clear_source_error() self.clear_target_error() self.source.setEnabled(not value) self.reverse.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) if value: self.reverse_old = self.reverse.isChecked() self.reverse.setChecked(True) else: self.reverse.setChecked(self.reverse_old) def flows_out_toggled(self, value): self.clear_source_error() self.clear_target_error() self.target.setEnabled(not value) self.reverse.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) if value: self.reverse_old = self.reverse.isChecked() self.reverse.setChecked(False) else: self.reverse.setChecked(self.reverse_old) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "The source domain of the analysis.") def set_source(self): try: # look up the type here, so invalid types can be caught immediately text = self.source.text() if text: self.query.source = self.policy.lookup_type(text) else: self.query.source = None except Exception as ex: self.log.error("Source domain error: {0}".format(str(ex))) self.set_criteria_error(self.source, ex) # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "The target domain of the analysis.") def set_target(self): try: # look up the type here, so invalid types can be caught immediately text = self.target.text() if text: self.query.target = self.policy.lookup_type(text) else: self.query.target = None except Exception as ex: self.log.error("Target domain error: {0}".format(str(ex))) self.set_criteria_error(self.target, ex) # # Options # def choose_excluded_types(self): chooser = ExcludeTypes(self, self.policy) chooser.show() def reverse_toggled(self, value): self.query.reverse = value # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out", "reverse"]) save_lineedits(self, settings, ["source", "target"]) save_spinboxes(self, settings, ["max_path_length", "limit_paths"]) save_textedits(self, settings, ["notes"]) settings["exclude"] = [str(t) for t in self.query.exclude] return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out", "reverse"]) load_lineedits(self, settings, ["source", "target"]) load_spinboxes(self, settings, ["max_path_length", "limit_paths"]) load_textedits(self, settings, ["notes"]) try: self.query.exclude = settings["exclude"] except KeyError: self.log.warning("Excluded types criteria missing from settings file.") # # Infoflow browser # def _new_browser_item(self, type_, parent, rules=None, children=None): # build main item item = QTreeWidgetItem(parent if parent else self.browser) item.setText(0, str(type_)) item.type_ = type_ item.children = children if children else [] item.rules = rules if rules else [] item.child_populated = children is not None # add child items for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.setExpanded(children is not None) self.log.debug("Built item for {0} with {1} children and {2} rules".format( type_, len(item.children), len(item.rules))) return item def reset_browser(self, root_type, out, children): self.log.debug("Resetting browser.") # clear results self.browser.clear() self.browser_details.clear() # save browser details independent # from main analysis UI settings self.browser_root_type = root_type self.browser_mode = out root = self._new_browser_item(self.browser_root_type, self.browser, children=children) self.browser.insertTopLevelItem(0, root) def browser_item_selected(self, current, previous): if not current: # browser is being reset return self.log.debug("{0} selected in browser.".format(current.type_)) self.browser_details.clear() try: parent_type = current.parent().type_ except AttributeError: # should only hit his on the root item pass else: self.browser_details.appendPlainText("Domain Transitions {0} {1} {2}\n".format( current.parent().type_, "->" if self.browser_mode else "<-", current.type_)) print_transition(self.browser_details.appendPlainText, current.rules) self.browser_details.moveCursor(QTextCursor.Start) if not current.child_populated: self.busy.setLabelText("Gathering additional browser details for {0}...".format( current.type_)) self.busy.show() self.browser_thread.out = self.browser_mode self.browser_thread.type_ = current.type_ self.browser_thread.start() def add_browser_children(self, children): item = self.browser.currentItem() item.children = children self.log.debug("Adding children for {0}".format(item.type_)) for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.child_populated = True self.busy.reset() # # Results runner # def run(self, button): # right now there is only one button. fail = False if self.source.isEnabled() and not self.query.source: self.set_criteria_error(self.source, "A source domain is required") if self.target.isEnabled() and not self.query.target: self.set_criteria_error(self.target, "A target domain is required.") if self.errors: return for mode in [self.all_paths, self.all_shortest_paths, self.flows_in, self.flows_out]: if mode.isChecked(): break self.query.mode = mode.objectName() self.query.max_path_len = self.max_path_length.value() self.query.limit = self.limit_paths.value() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self): if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) if self.flows_in.isChecked() or self.flows_out.isChecked(): # move to browser tab for transitions in/out self.results_frame.setCurrentIndex(1) else: self.results_frame.setCurrentIndex(0) self.busy.reset() def sort_transition(trans): """Sort the rules of a transition in-place.""" trans.transition.sort() trans.setexec.sort() trans.entrypoints.sort() trans.dyntransition.sort() trans.setcurrent.sort() for e in trans.entrypoints: e.entrypoint.sort() e.execute.sort() e.type_transition.sort() def print_transition(renderer, trans): """ Raw rendering of a domain transition. Parameters: renderer A callable which will render the output, e.g. print trans A step (transition object) generated by the DTA. """ if trans.transition: renderer("Domain transition rule(s):") for t in trans.transition: renderer(str(t)) if trans.setexec: renderer("\nSet execution context rule(s):") for s in trans.setexec: renderer(str(s)) for entrypoint in trans.entrypoints: renderer("\nEntrypoint {0}:".format(entrypoint.name)) renderer("\tDomain entrypoint rule(s):") for e in entrypoint.entrypoint: renderer("\t{0}".format(e)) renderer("\n\tFile execute rule(s):") for e in entrypoint.execute: renderer("\t{0}".format(e)) if entrypoint.type_transition: renderer("\n\tType transition rule(s):") for t in entrypoint.type_transition: renderer("\t{0}".format(t)) renderer("") if trans.dyntransition: renderer("Dynamic transition rule(s):") for d in trans.dyntransition: renderer(str(d)) renderer("\nSet current process context rule(s):") for s in trans.setcurrent: renderer(str(s)) renderer("") renderer("") class ResultsUpdater(QThread): """ Thread for processing queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: raw_line (str) A string to be appended to the raw results. trans (str, bool, list) Initial information for populating the transitions browser. """ raw_line = pyqtSignal(str) trans = pyqtSignal(str, bool, list) def __init__(self, query): super(ResultsUpdater, self).__init__() self.query = query self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): """Run the query and update results.""" assert self.query.limit, "Code doesn't currently handle unlimited (limit=0) paths." self.out = self.query.mode == "flows_out" if self.query.mode == "all_paths": self.transitive(self.query.all_paths(self.query.source, self.query.target, self.query.max_path_len)) elif self.query.mode == "all_shortest_paths": self.transitive(self.query.all_shortest_paths(self.query.source, self.query.target)) elif self.query.mode == "flows_out": self.direct(self.query.transitions(self.query.source)) else: # flows_in self.direct(self.query.transitions(self.query.target)) def transitive(self, paths): i = 0 for i, path in enumerate(paths, start=1): self.raw_line.emit("Domain transition path {0}:".format(i)) for stepnum, step in enumerate(path, start=1): self.raw_line.emit("Step {0}: {1} -> {2}\n".format(stepnum, step.source, step.target)) sort_transition(step) print_transition(self.raw_line.emit, step) if QThread.currentThread().isInterruptionRequested() or (i >= self.query.limit): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} domain transition path(s) found.".format(i)) self.log.info("{0} domain transition path(s) found.".format(i)) def direct(self, transitions): i = 0 child_types = [] for i, step in enumerate(transitions, start=1): self.raw_line.emit("Transition {0}: {1} -> {2}\n".format(i, step.source, step.target)) sort_transition(step) print_transition(self.raw_line.emit, step) # Generate results for flow browser if self.out: child_types.append((step.target, step)) else: child_types.append((step.source, step)) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} domain transition(s) found.".format(i)) self.log.info("{0} domain transition(s) found.".format(i)) # Update browser: root_type = self.query.source if self.out else self.query.target self.trans.emit(str(root_type), self.out, sorted(child_types)) class BrowserUpdater(QThread): """ Thread for processing additional analysis for the browser. Parameters: query The query object model The model for the results Qt signals: trans A list of child types to render in the transitions browser. """ trans = pyqtSignal(list) def __init__(self, query): super(BrowserUpdater, self).__init__() self.query = query self.type_ = None self.out = None self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): transnum = 0 child_types = [] for transnum, trans in enumerate(self.query.transitions(self.type_), start=1): # Generate results for browser sort_transition(trans) if self.out: child_types.append((trans.target, trans)) else: child_types.append((trans.source, trans)) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.log.debug("{0} additional domain transition(s) found.".format(transnum)) # Update browser: self.trans.emit(sorted(child_types)) setools-4.4.0/setoolsgui/apol/dta.ui000066400000000000000000000467021402045477700174710ustar00rootroot00000000000000 DomainTransitionAnalysisTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show or hide the search criteria (no settings are lost) Criteria true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 Options 3 3 6 6 6 6 Limit results: 1 1000 20 Excluded Types: Edit... Reverse: Analyze reverse (parent) domain transitions instead of forward (child) domain transitions. 16777215 100 Target Domain 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 16777215 100 Source Domain 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 QDialogButtonBox::Apply Analysis Mode 6 6 6 6 3 The limit for path length. steps 1 3 All domain transitions into the target domain will be shown. Transitions into the target domain All paths from the source domain to the target domain, up to the specified maximum length, will be shown. All paths up to All shortest paths from the source domain to the target domain will be shown. Shortest paths true All domain transitions out of the source domain will be shown. Transitions out of the source domain source_criteria target_criteria buttonBox groupBox groupBox_2 0 0 16777215 20 12 75 true Domain Transition Analysis Show: Qt::Horizontal 40 20 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes 0 1 0 0 0 Raw Results 3 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Browser Qt::Horizontal 1 0 Type 4 0 Monospace SEToolsTreeWidget QTreeWidget
setoolsgui/treeview.h
criteria_expander notes_expander source target all_shortest_paths all_paths max_path_length flows_out flows_in reverse limit_paths exclude_types results_frame raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 589 16 386 164 notes_expander toggled(bool) notes setVisible(bool) 732 16 386 705
setools-4.4.0/setoolsgui/apol/exception.py000066400000000000000000000015151402045477700207230ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # class TabFieldError(RuntimeError): """Exception when trying to save a tab that has errors.""" pass setools-4.4.0/setoolsgui/apol/exclude_types.ui000066400000000000000000000117521402045477700215730ustar00rootroot00000000000000 Dialog 0 0 619 340 Exclude Types From Analysis 0 0 16777215 20 11 75 true Included Types 0 0 16777215 20 11 75 true Excluded Types Qt::Vertical 20 40 Exclude selected types. Include selected types. Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok 150 16777215 Filter types by attribute: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QAbstractItemView::ExtendedSelection QAbstractItemView::ExtendedSelection buttonBox accepted() Dialog accept() 248 254 157 274 buttonBox rejected() Dialog reject() 316 260 286 274 setools-4.4.0/setoolsgui/apol/excludetypes.py000066400000000000000000000123551402045477700214470ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from PyQt5.QtCore import Qt, QSortFilterProxyModel from PyQt5.QtWidgets import QDialog from ..models import SEToolsListModel from ..widget import SEToolsWidget class ExcludeTypes(SEToolsWidget, QDialog): """Dialog for choosing excluded types.""" def __init__(self, parent, policy): super(ExcludeTypes, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.policy = policy self.initial_excluded_list = copy.copy(self.parent.query.exclude) self.setupUi() def setupUi(self): self.load_ui("apol/exclude_types.ui") # populate the attribute combo box: self.attr_model = SEToolsListModel(self) self.attr_model.item_list = [""] + sorted(self.policy.typeattributes()) self.attr.setModel(self.attr_model) # populate the models: self.included_model = SEToolsListModel(self) self.included_model.item_list = [t for t in self.policy.types() if t not in self.initial_excluded_list] self.included_sort = FilterByAttributeProxy(self) self.included_sort.setSourceModel(self.included_model) self.included_sort.sort(0, Qt.AscendingOrder) self.included_types.setModel(self.included_sort) self.excluded_model = SEToolsListModel(self) self.excluded_model.item_list = self.initial_excluded_list self.excluded_sort = FilterByAttributeProxy(self) self.excluded_sort.setSourceModel(self.excluded_model) self.excluded_sort.sort(0, Qt.AscendingOrder) self.excluded_types.setModel(self.excluded_sort) # connect signals self.exclude_a_type.clicked.connect(self.exclude_clicked) self.include_a_type.clicked.connect(self.include_clicked) self.attr.currentIndexChanged.connect(self.set_attr_filter) def include_clicked(self): included_scroll_pos = self.included_types.verticalScrollBar().value() excluded_scroll_pos = self.excluded_types.verticalScrollBar().value() selected_types = [] for index in self.excluded_types.selectionModel().selectedIndexes(): source_index = self.excluded_sort.mapToSource(index) item = self.excluded_model.data(source_index, Qt.UserRole) self.included_model.append(item) selected_types.append(item) self.log.debug("Including {0}".format(selected_types)) for item in selected_types: self.excluded_model.remove(item) self.included_types.verticalScrollBar().setValue(included_scroll_pos) self.excluded_types.verticalScrollBar().setValue(excluded_scroll_pos) def exclude_clicked(self): included_scroll_pos = self.included_types.verticalScrollBar().value() excluded_scroll_pos = self.excluded_types.verticalScrollBar().value() selected_types = [] for index in self.included_types.selectionModel().selectedIndexes(): source_index = self.included_sort.mapToSource(index) item = self.included_model.data(source_index, Qt.UserRole) self.excluded_model.append(item) selected_types.append(item) self.log.debug("Excluding {0}".format(selected_types)) for item in selected_types: self.included_model.remove(item) self.included_types.verticalScrollBar().setValue(included_scroll_pos) self.excluded_types.verticalScrollBar().setValue(excluded_scroll_pos) def set_attr_filter(self, row): index = self.attr_model.index(row) attr = self.attr_model.data(index, Qt.UserRole) self.log.debug("Attribute set to {0!r}".format(attr)) self.included_sort.attr = attr self.excluded_sort.attr = attr def accept(self): self.log.debug("Chosen for exclusion: {0!r}".format(self.excluded_model.item_list)) self.parent.query.exclude = self.excluded_model.item_list super(ExcludeTypes, self).accept() class FilterByAttributeProxy(QSortFilterProxyModel): """Filter a list of types by attribute membership.""" _attr = None @property def attr(self): return self._attr @attr.setter def attr(self, value): self._attr = value self.invalidateFilter() def filterAcceptsRow(self, row, parent): if self.attr: source = self.sourceModel() index = source.index(row) item = source.data(index, Qt.UserRole) if item not in self.attr: return False return True setools-4.4.0/setoolsgui/apol/fsusequery.py000066400000000000000000000306551402045477700211470ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import FSUseQuery from ..logtosignal import LogHandlerToSignal from ..fsusemodel import FSUseTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class FSUseQueryTab(AnalysisTab): """A fs_use_* rule query.""" section = AnalysisSection.Labeling tab_title = "Fs_use_* Statements" mlsonly = False def __init__(self, parent, policy, perm_map): super(FSUseQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = FSUseQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.fsusequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/fsusequery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_fs_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = FSUseTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.fsusequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_fs_regex(self.fs_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.fs.textEdited.connect(self.clear_fs_error) self.fs.editingFinished.connect(self.set_fs) self.fs_regex.toggled.connect(self.set_fs_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Ruletype criteria # def _set_ruletypes(self, value): self.fs_use_xattr.setChecked(value) self.fs_use_trans.setChecked(value) self.fs_use_task.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # FS criteria # def clear_fs_error(self): self.clear_criteria_error(self.fs, "Match the filesystem type.") def set_fs(self): try: self.query.fs = self.fs.text() except Exception as ex: self.log.error("Filesystem type error: {0}".format(ex)) self.set_criteria_error(self.fs, ex) def set_fs_regex(self, state): self.log.debug("Setting fs_regex {0}".format(state)) self.query.fs_regex = state self.clear_fs_error() self.set_fs() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "fs_use_xattr", "fs_use_trans", "fs_use_task", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["fs", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.fs_use_xattr, self.fs_use_trans, self.fs_use_task]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} fs_use_* statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/fsusequery.ui000066400000000000000000000617341402045477700211360ustar00rootroot00000000000000 FSUseQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true fs_use_* Statements 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal 40 20 Filesystem Type Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Qt::Horizontal 40 20 fs_use_xattr true Clear false fs_use_task true fs_use_trans true QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 250 16777215 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 role_criteria type_criteria user_critera ruletype_criteria fs_criteria range_criteria buttonBox Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander fs_use_xattr fs_use_task fs_use_trans clear_ruletypes all_ruletypes fs fs_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/genfsconquery.py000066400000000000000000000306751402045477700216260ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import GenfsconQuery from ..logtosignal import LogHandlerToSignal from ..genfsconmodel import GenfsconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class GenfsconQueryTab(AnalysisTab): """A fs_use_* rule query.""" section = AnalysisSection.Labeling tab_title = "Genfscon Statements" mlsonly = False def __init__(self, parent, policy, perm_map): super(GenfsconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = GenfsconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.genfsconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/genfsconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_fs_error() self.clear_path_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = GenfsconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.genfsconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_fs_regex(self.fs_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.fs.textEdited.connect(self.clear_fs_error) self.fs.editingFinished.connect(self.set_fs) self.fs_regex.toggled.connect(self.set_fs_regex) self.path.textEdited.connect(self.clear_path_error) self.path.editingFinished.connect(self.set_path) self.path_regex.toggled.connect(self.set_path_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # FS criteria # def clear_fs_error(self): self.clear_criteria_error(self.fs, "Match the filesystem type.") def set_fs(self): try: self.query.fs = self.fs.text() except Exception as ex: self.log.error("Filesystem type error: {0}".format(ex)) self.set_criteria_error(self.fs, ex) def set_fs_regex(self, state): self.log.debug("Setting fs_regex {0}".format(state)) self.query.fs_regex = state self.clear_fs_error() self.set_fs() # # Path criteria # def clear_path_error(self): self.clear_criteria_error(self.path, "Match the path.") def set_path(self): try: self.query.path = self.path.text() except Exception as ex: self.log.error("Path error: {0}".format(ex)) self.set_criteria_error(self.path, ex) def set_path_regex(self, state): self.log.debug("Setting path_regex {0}".format(state)) self.query.path_regex = state self.clear_path_error() self.set_path() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "path_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["fs", "path", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "fs_regex", "path_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["fs", "path", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} genfscon(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/genfsconquery.ui000066400000000000000000000566201402045477700216110ustar00rootroot00000000000000 GenfsconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Genfscon Statements Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised Filesystem Type Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Path Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Context User 0 0 150 0 250 16777215 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset Match the context's range if the criteria overlaps the context's range. Overlap 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander fs fs_regex path path_regex user user_regex role role_regex type_ type_regex range_ range_exact range_subset range_overlap range_superset results_frame table_results notes raw_results criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/ibendportconquery.py000066400000000000000000000302651402045477700225050ustar00rootroot00000000000000# Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QProgressDialog from setools import IbendportconQuery from ..logtosignal import LogHandlerToSignal from ..ibendportconmodel import IbendportconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class IbendportconQueryTab(AnalysisTab): """An ibendportcon query.""" section = AnalysisSection.Labeling tab_title = "Infiniband Endport Contexts" mlsonly = False def __init__(self, parent, policy, perm_map): super().__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = IbendportconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.ibendportconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/ibendportconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() self.clear_port_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = IbendportconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.ibendportconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.port.textEdited.connect(self.clear_port_error) self.port.editingFinished.connect(self.set_port) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Subnet prefix criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the device name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Device name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Port criteria # def clear_port_error(self): self.clear_criteria_error(self.port, "Match the endport.") def set_port(self): try: self.query.port = self.port.text() except Exception as ex: self.log.error("Endport error: {0}".format(ex)) self.set_criteria_error(self.port, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "port", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "port", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} ibendportcon statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/ibendportconquery.ui000066400000000000000000000563051402045477700224750ustar00rootroot00000000000000 NetifconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Infiniband Endport Contexts 16777215 16777215 QFrame::StyledPanel QFrame::Raised Device Name Use regular expressions to match the device name. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Endport 0 0 150 0 250 16777215 e.g. 80 Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply role_criteria type_criteria user_critera range_criteria buttonBox name_criteria port_criteria Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander name name_regex port user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/ibpkeyconquery.py000066400000000000000000000320201402045477700217710ustar00rootroot00000000000000# Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QProgressDialog from setools import IbpkeyconQuery from ..logtosignal import LogHandlerToSignal from ..ibpkeyconmodel import IbpkeyconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class IbpkeyconQueryTab(AnalysisTab): """An ibpkeycon query.""" section = AnalysisSection.Labeling tab_title = "Infiniband Partition Key Contexts" mlsonly = False def __init__(self, parent, policy, perm_map): super().__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = IbpkeyconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.ibpkeyconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/ibpkeyconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_subnet_prefix_error() self.clear_pkeys_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = IbpkeyconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.ibpkeyconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.subnet_prefix.textEdited.connect(self.clear_subnet_prefix_error) self.subnet_prefix.editingFinished.connect(self.set_subnet_prefix) self.pkeys.textEdited.connect(self.clear_pkeys_error) self.pkeys.editingFinished.connect(self.set_pkeys) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Subnet prefix criteria # def clear_subnet_prefix_error(self): self.clear_criteria_error(self.subnet_prefix, "Match the subnet prefix.") def set_subnet_prefix(self): try: self.query.subnet_prefix = self.subnet_prefix.text() except Exception as ex: self.log.error("Subnet prefix error: {0}".format(ex)) self.set_criteria_error(self.subnet_prefix, ex) # # Pkey criteria # def clear_pkeys_error(self): self.clear_criteria_error(self.pkeys, "Match the partition keys.") def set_pkeys(self): try: pending_pkeys = self.pkeys.text() if pending_pkeys: try: pkeys = [int(i) for i in pending_pkeys.split("-")] except ValueError as ex: raise ValueError("Enter a pkey number or range, e.g. 22 or 6000-6020") from ex if len(pkeys) == 2: self.query.pkeys = pkeys elif len(pkeys) == 1: self.query.pkeys = (pkeys[0], pkeys[0]) else: raise ValueError("Enter a pkey number or range, e.g. 22 or 6000-6020") else: self.query.pkeys = None except Exception as ex: self.log.error("Partition key error: {0}".format(ex)) self.set_criteria_error(self.pkeys, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "pkeys_exact", "pkeys_overlap", "pkeys_subset", "pkeys_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["subnet_prefix", "pkeys", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "pkeys_exact", "pkeys_overlap", "pkeys_subset", "pkeys_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["subnet_prefix", "pkeys", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.pkeys_overlap = self.pkeys_overlap.isChecked() self.query.pkeys_subset = self.pkeys_subset.isChecked() self.query.pkeys_superset = self.pkeys_superset.isChecked() self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} ibpkeycon statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/ibpkeyconquery.ui000066400000000000000000000641621402045477700217720ustar00rootroot00000000000000 PortconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Infiniband Partition Key Contexts Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised Subnet Prefix 0 0 150 0 250 16777215 e.g. ff00:: false Match the subnet mask if the criteria is equal to the ibpkeycon's subnet prefix. Equal true false Match the subnet prefix if the criteria overlaps the ibpkeycon's subnet prefix. Overlap false Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply Partition Keys 0 0 150 0 250 16777215 e.g. 80 or 6000-6010 Match the port range if the criteria is a superset to the portcon's port range. Superset Match the port range if the criteria overlaps the portcon's port range. Overlap true Match the port range if the criteria is equal to the portcon's port range. Equal false Match the port range if the criteria is a subset of the portcon's port range. Subset Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox pkeys_criteria subnet_prefix_criteria SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander subnet_prefix subnet_prefix_exact subnet_prefix_overlap pkeys pkeys_exact pkeys_overlap pkeys_subset pkeys_superset user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/infoflow.py000066400000000000000000000475621402045477700205640ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from collections import defaultdict from contextlib import suppress from PyQt5.QtCore import pyqtSignal, Qt, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog, \ QTreeWidgetItem from setools import InfoFlowAnalysis from setools.exception import UnmappedClass, UnmappedPermission from ..logtosignal import LogHandlerToSignal from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .excludetypes import ExcludeTypes from .permmapedit import PermissionMapEditor from .workspace import load_checkboxes, load_spinboxes, load_lineedits, load_textedits, \ save_checkboxes, save_spinboxes, save_lineedits, save_textedits class InfoFlowAnalysisTab(AnalysisTab): """An information flow analysis tab.""" section = AnalysisSection.Analysis tab_title = "Information Flow Analysis" mlsonly = False @property def perm_map(self): return self.query.perm_map @perm_map.setter def perm_map(self, pmap): # copy permission map to keep enabled/disabled # settings private to this map. perm_map = copy.deepcopy(pmap) # transfer enabled/disabled settings from # current permission map, to the new map for classname in self.query.perm_map.classes(): for mapping in self.query.perm_map.perms(classname): with suppress(UnmappedClass, UnmappedPermission): perm_map.mapping(classname, mapping.perm).enabled = mapping.enabled # apply updated permission map self.query.perm_map = perm_map def __init__(self, parent, policy, perm_map): super(InfoFlowAnalysisTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = InfoFlowAnalysis(policy, perm_map) self.query.source = None self.query.target = None self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.infoflow").removeHandler(self.handler) def setupUi(self): self.log.debug("Initializing UI.") self.load_ui("apol/infoflow.ui") # set up error message for missing perm map self.error_msg = QMessageBox(self) self.error_msg.setStandardButtons(QMessageBox.Ok) # set up perm map editor self.permmap_editor = PermissionMapEditor(self, False) # set up source/target autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.source.setCompleter(self.type_completion) self.target.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() # set up processing thread self.thread = ResultsUpdater(self.query) self.thread.raw_line.connect(self.raw_results.appendPlainText) self.thread.finished.connect(self.update_complete) self.thread.flows.connect(self.reset_browser) # set up browser thread self.browser_thread = BrowserUpdater(self.query) self.browser_thread.flows.connect(self.add_browser_children) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.setCancelButton(None) self.busy.reset() # update busy dialog from infoflow INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.infoflow").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.max_path_length.setEnabled(self.all_paths.isChecked()) self.source.setEnabled(not self.flows_in.isChecked()) self.target.setEnabled(not self.flows_out.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) self.browser_tab.setEnabled(self.flows_in.isChecked() or self.flows_out.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.all_paths.toggled.connect(self.all_paths_toggled) self.flows_in.toggled.connect(self.flows_in_toggled) self.flows_out.toggled.connect(self.flows_out_toggled) self.min_perm_weight.valueChanged.connect(self.set_min_weight) self.exclude_types.clicked.connect(self.choose_excluded_types) self.edit_permmap.clicked.connect(self.open_permmap_editor) self.browser.currentItemChanged.connect(self.browser_item_selected) # # Analysis mode # def all_paths_toggled(self, value): self.clear_source_error() self.clear_target_error() self.max_path_length.setEnabled(value) def flows_in_toggled(self, value): self.clear_source_error() self.clear_target_error() self.source.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) def flows_out_toggled(self, value): self.clear_source_error() self.clear_target_error() self.target.setEnabled(not value) self.limit_paths.setEnabled(not value) self.browser_tab.setEnabled(value) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "The source type of the analysis.") def set_source(self): try: # look up the type here, so invalid types can be caught immediately text = self.source.text() if text: self.query.source = self.policy.lookup_type(text) else: self.query.source = None except Exception as ex: self.log.error("Source type error: {0}".format(str(ex))) self.set_criteria_error(self.source, ex) # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "The target type of the analysis.") def set_target(self): try: # look up the type here, so invalid types can be caught immediately text = self.target.text() if text: self.query.target = self.policy.lookup_type(text) else: self.query.target = None except Exception as ex: self.log.error("Target type error: {0}".format(str(ex))) self.set_criteria_error(self.target, ex) # # Options # def set_min_weight(self, value): self.query.min_weight = value def choose_excluded_types(self): chooser = ExcludeTypes(self, self.policy) chooser.show() def open_permmap_editor(self): self.permmap_editor.show(self.perm_map) def apply_permmap(self, pmap): # used only by permission map editor self.query.perm_map = pmap # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out"]) save_lineedits(self, settings, ["source", "target"]) save_spinboxes(self, settings, ["max_path_length", "limit_paths", "min_perm_weight"]) save_textedits(self, settings, ["notes"]) settings["exclude"] = [str(t) for t in self.query.exclude] settings["exclude_perms"] = defaultdict(list) for mapping in self.perm_map: if not mapping.enabled: settings["exclude_perms"][mapping.class_].append(mapping.perm) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "all_paths", "all_shortest_paths", "flows_in", "flows_out"]) load_lineedits(self, settings, ["source", "target"]) load_spinboxes(self, settings, ["max_path_length", "limit_paths", "min_perm_weight"]) load_textedits(self, settings, ["notes"]) try: self.query.exclude = settings["exclude"] except KeyError: self.log.warning("Excluded types criteria missing from settings file.") if "exclude_perms" not in settings: self.log.warning("Excluded permissions missing from settings file.") else: for mapping in self.perm_map: # iterate over the map so that any permission # not in the setting file's exclude list is enabled. try: mapping.enabled = mapping.perm not in settings["exclude_perms"][mapping.class_] except KeyError: mapping.enabled = True # # Infoflow browser # def _new_browser_item(self, type_, parent, rules=None, children=None): # build main item item = QTreeWidgetItem(parent if parent else self.browser) item.setText(0, str(type_)) item.type_ = type_ item.children = children if children else [] item.rules = rules if rules else [] item.child_populated = children is not None # add child items for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.setExpanded(children is not None) self.log.debug("Built item for {0} with {1} children and {2} rules".format( type_, len(item.children), len(item.rules))) return item def reset_browser(self, root_type, out, children): self.log.debug("Resetting browser.") # clear results self.browser.clear() self.browser_details.clear() # save browser details independent # from main analysis UI settings self.browser_root_type = root_type self.browser_mode = out root = self._new_browser_item(self.browser_root_type, self.browser, children=children) self.browser.insertTopLevelItem(0, root) def browser_item_selected(self, current, previous): if not current: # browser is being reset return self.log.debug("{0} selected in browser.".format(current.type_)) self.browser_details.clear() try: parent_type = current.parent().type_ except AttributeError: # should only hit his on the root item pass else: self.browser_details.appendPlainText("Information flows {0} {1} {2}\n".format( current.parent().type_, "->" if self.browser_mode else "<-", current.type_)) for rule in current.rules: self.browser_details.appendPlainText(rule) self.browser_details.moveCursor(QTextCursor.Start) if not current.child_populated: self.busy.setLabelText("Gathering additional browser details for {0}...".format( current.type_)) self.busy.show() self.browser_thread.out = self.browser_mode self.browser_thread.type_ = current.type_ self.browser_thread.start() def add_browser_children(self, children): item = self.browser.currentItem() item.children = children self.log.debug("Adding children for {0}".format(item.type_)) for child_type, child_rules in item.children: child_item = self._new_browser_item(child_type, item, rules=child_rules) item.addChild(child_item) item.child_populated = True self.busy.reset() # # Results runner # def run(self, button): # right now there is only one button. fail = False if self.source.isEnabled() and not self.query.source: self.set_criteria_error(self.source, "A source type is required") fail = True if self.target.isEnabled() and not self.query.target: self.set_criteria_error(self.target, "A target type is required.") fail = True if not self.perm_map: self.log.critical("A permission map is required to begin the analysis.") self.error_msg.critical(self, "No permission map available.", "Please load a permission map to begin the analysis.") fail = True if fail: return for mode in [self.all_paths, self.all_shortest_paths, self.flows_in, self.flows_out]: if mode.isChecked(): break self.query.mode = mode.objectName() self.query.max_path_len = self.max_path_length.value() self.query.limit = self.limit_paths.value() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self): if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) if self.flows_in.isChecked() or self.flows_out.isChecked(): # move to browser tab for flows in/out self.results_frame.setCurrentIndex(1) else: self.results_frame.setCurrentIndex(0) self.busy.reset() class ResultsUpdater(QThread): """ Thread for processing queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: raw_line A string to be appended to the raw results. flows (str, bool, list) Initial information for populating the flows browser. """ raw_line = pyqtSignal(str) flows = pyqtSignal(str, bool, list) def __init__(self, query): super(ResultsUpdater, self).__init__() self.query = query self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): """Run the query and update results.""" assert self.query.limit, "Code doesn't currently handle unlimited (limit=0) paths." self.out = self.query.mode == "flows_out" if self.query.mode == "all_paths": self.transitive(self.query.all_paths(self.query.source, self.query.target, self.query.max_path_len)) elif self.query.mode == "all_shortest_paths": self.transitive(self.query.all_shortest_paths(self.query.source, self.query.target)) elif self.query.mode == "flows_out": self.direct(self.query.infoflows(self.query.source, out=self.out)) else: # flows_in self.direct(self.query.infoflows(self.query.target, out=self.out)) def transitive(self, paths): pathnum = 0 for pathnum, path in enumerate(paths, start=1): self.raw_line.emit("Flow {0}:".format(pathnum)) for stepnum, step in enumerate(path, start=1): self.raw_line.emit(" Step {0}: {1} -> {2}".format(stepnum, step.source, step.target)) for rule in sorted(step.rules): self.raw_line.emit(" {0}".format(rule)) self.raw_line.emit("") if QThread.currentThread().isInterruptionRequested() or (pathnum >= self.query.limit): break else: QThread.yieldCurrentThread() self.raw_line.emit("") self.raw_line.emit("{0} information flow path(s) found.\n".format(pathnum)) self.log.info("{0} information flow path(s) found.".format(pathnum)) def direct(self, flows): flownum = 0 child_types = [] for flownum, flow in enumerate(flows, start=1): self.raw_line.emit("Flow {0}: {1} -> {2}".format(flownum, flow.source, flow.target)) for rule in sorted(flow.rules): self.raw_line.emit(" {0}".format(rule)) self.raw_line.emit("") # Generate results for flow browser if self.out: child_types.append((flow.target, sorted(str(r) for r in flow.rules))) else: child_types.append((flow.source, sorted(str(r) for r in flow.rules))) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.raw_line.emit("{0} information flow(s) found.\n".format(flownum)) self.log.info("{0} information flow(s) found.".format(flownum)) # Update browser: root_type = self.query.source if self.out else self.query.target self.flows.emit(str(root_type), self.out, sorted(child_types)) class BrowserUpdater(QThread): """ Thread for processing additional analysis for the browser. Parameters: query The query object model The model for the results Qt signals: flows A list of child types to render in the infoflows browser. """ flows = pyqtSignal(list) def __init__(self, query): super(BrowserUpdater, self).__init__() self.query = query self.type_ = None self.out = None self.log = logging.getLogger(__name__) def __del__(self): self.wait() def run(self): flownum = 0 child_types = [] for flownum, flow in enumerate(self.query.infoflows(self.type_, out=self.out), start=1): # Generate results for flow browser if self.out: child_types.append((flow.target, sorted(str(r) for r in flow.rules))) else: child_types.append((flow.source, sorted(str(r) for r in flow.rules))) if QThread.currentThread().isInterruptionRequested(): break else: QThread.yieldCurrentThread() self.log.debug("{0} additional information flow(s) found.".format(flownum)) # Update browser: self.flows.emit(sorted(child_types)) setools-4.4.0/setoolsgui/apol/infoflow.ui000066400000000000000000000473221402045477700205430ustar00rootroot00000000000000 InfoflowAnalysisTab 0 0 774 846 0 0 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 Options 3 3 6 6 6 6 Minimum permission weight: 1 10 Limit results: 1 1000 20 Excluded Types: Edit... Edit... Excluded Permissions: 16777215 100 Target Type 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 16777215 100 Source Type 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 QDialogButtonBox::Apply Analysis Mode 6 6 6 6 3 The limit for path length. steps 1 3 All information flows into the target type will be shown. Flows into the target type All paths from the source type to the target type, up to the specified maximum length, will be shown. All paths up to All shortest paths from the source type to the target type will be shown. Shortest paths true All information flows out of the source type will be shown. Flows out of the source type source_criteria target_criteria buttonBox groupBox groupBox_2 0 0 16777215 20 12 75 true Information Flow Analysis Qt::Horizontal 40 20 Show: 0 1 0 0 0 Raw Results 3 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true true Browser Qt::Horizontal 1 0 Type 4 0 Monospace Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 0 0 80 Optionally enter notes here about the query. Enter notes here. SEToolsTreeWidget QTreeWidget
setoolsgui/treeview.h
criteria_expander notes_expander source target all_shortest_paths all_paths max_path_length flows_out flows_in min_perm_weight limit_paths exclude_types results_frame raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 19 386 174 notes_expander toggled(bool) notes setVisible(bool) 732 19 386 708
setools-4.4.0/setoolsgui/apol/initsidquery.py000066400000000000000000000271731402045477700214660ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import InitialSIDQuery from ..logtosignal import LogHandlerToSignal from ..initsidmodel import InitialSIDTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class InitialSIDQueryTab(AnalysisTab): """An initial SID query.""" section = AnalysisSection.Labeling tab_title = "Initial SID Statements" mlsonly = False def __init__(self, parent, policy, perm_map): super(InitialSIDQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = InitialSIDQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.initsidquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/initsidquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = InitialSIDTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.initsidquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} initial SID statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/initsidquery.ui000066400000000000000000000532641402045477700214530ustar00rootroot00000000000000 InitialSIDQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Initial SID Statements 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Name Use regular expressions to match the filesystem type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox name_criteria Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander name name_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/mainwindow.py000066400000000000000000000712321402045477700211040ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import shutil import logging import json from contextlib import suppress import pkg_resources from PyQt5.QtCore import pyqtSlot, Qt, QProcess from PyQt5.QtWidgets import QApplication, QFileDialog, QLineEdit, QMainWindow, QMessageBox from setools import __version__, PermissionMap, SELinuxPolicy from ..widget import SEToolsWidget from ..logtosignal import LogHandlerToSignal from .analysistab import TAB_REGISTRY from .chooseanalysis import ChooseAnalysis from .config import ApolConfig from .exception import TabFieldError from .permmapedit import PermissionMapEditor from .summary import SummaryTab BIN_SEARCH_PATHS = ("/usr/local/bin:/usr/bin:/bin") POSSIBLE_ASSISTANT = ("assistant", "assistant-qt5") class ApolMainWindow(SEToolsWidget, QMainWindow): def __init__(self, filename): super(ApolMainWindow, self).__init__() self.log = logging.getLogger(__name__) self._permmap = None self._policy = None self.config = ApolConfig() self.setupUi() self.load_permmap() if filename: self.load_policy(filename) if self._policy: self.create_new_analysis("Summary", SummaryTab) self.update_window_title() self.toggle_workspace_actions() def setupUi(self): self.load_ui("apol/apol.ui") self.tab_counter = 0 # set up analysis menu self.chooser = ChooseAnalysis(self) # set up error message dialog self.error_msg = QMessageBox(self) self.error_msg.setStandardButtons(QMessageBox.Ok) # set up permission map editor self.permmap_editor = PermissionMapEditor(self, True) # set up tab name editor self.tab_editor = QLineEdit(self.AnalysisTabs) self.tab_editor.setWindowFlags(Qt.Popup) # configure tab bar context menu tabBar = self.AnalysisTabs.tabBar() tabBar.addAction(self.rename_tab_action) tabBar.addAction(self.close_tab_action) tabBar.setContextMenuPolicy(Qt.ActionsContextMenu) # capture INFO and higher Python messages from setools lib for status bar handler = LogHandlerToSignal() handler.message.connect(self.statusbar.showMessage) logging.getLogger("setools").addHandler(handler) logging.getLogger("setoolsgui").addHandler(handler) # set up help browser process self.help_process = QProcess() # connect signals self.open_policy.triggered.connect(self.select_policy) self.close_policy_action.triggered.connect(self.close_policy) self.open_permmap.triggered.connect(self.select_permmap) self.new_analysis.triggered.connect(self.choose_analysis) self.AnalysisTabs.currentChanged.connect(self.toggle_workspace_actions) self.AnalysisTabs.tabCloseRequested.connect(self.close_tab) self.AnalysisTabs.tabBarDoubleClicked.connect(self.tab_name_editor) self.tab_editor.editingFinished.connect(self.rename_tab) self.rename_tab_action.triggered.connect(self.rename_active_tab) self.close_tab_action.triggered.connect(self.close_active_tab) self.new_from_settings_action.triggered.connect(self.new_analysis_from_config) self.load_settings_action.triggered.connect(self.load_settings) self.save_settings_action.triggered.connect(self.save_settings) self.load_workspace_action.triggered.connect(self.load_workspace) self.save_workspace_action.triggered.connect(self.save_workspace) self.copy_action.triggered.connect(self.copy) self.cut_action.triggered.connect(self.cut) self.paste_action.triggered.connect(self.paste) self.edit_permmap_action.triggered.connect(self.edit_permmap) self.save_permmap_action.triggered.connect(self.save_permmap) self.about_apol_action.triggered.connect(self.about_apol) self.apol_help_action.triggered.connect(self.apol_help) self.help_process.errorOccurred.connect(self.help_failed) self.show() def update_window_title(self): if self._policy: self.setWindowTitle("{0} - apol".format(self._policy)) else: self.setWindowTitle("apol") # # Policy handling # def select_policy(self): old_policy = self._policy if old_policy and self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Loading a policy will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return filename = QFileDialog.getOpenFileName(self, "Open policy file", ".", "SELinux Policies (policy.* sepolicy);;" "All Files (*)")[0] if filename: self.load_policy(filename) if self._policy != old_policy: # policy loading succeeded, clear any # existing tabs self.AnalysisTabs.clear() self.create_new_analysis("Summary", SummaryTab) def load_policy(self, filename): try: self._policy = SELinuxPolicy(filename) except Exception as ex: self.log.critical("Failed to load policy \"{0}\"".format(filename)) self.error_msg.critical(self, "Policy loading error", str(ex)) else: self.update_window_title() self.toggle_workspace_actions() if self._permmap: self._permmap.map_policy(self._policy) self.apply_permmap() def close_policy(self): if self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Closing a policy will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return self.AnalysisTabs.clear() self._policy = None self.update_window_title() self.toggle_workspace_actions() # # Permission map handling # def select_permmap(self): filename = QFileDialog.getOpenFileName(self, "Open permission map file", ".")[0] if filename: self.load_permmap(filename) def load_permmap(self, filename=None): try: self._permmap = PermissionMap(filename) except Exception as ex: self.log.critical("Failed to load default permission map: {0}".format(ex)) self.error_msg.critical(self, "Permission map loading error", str(ex)) else: if self._policy: self._permmap.map_policy(self._policy) self.apply_permmap() def edit_permmap(self): if not self._permmap: self.error_msg.critical(self, "No open permission map", "Cannot edit permission map. Please open a map first.") self.select_permmap() # in case user cancels out of # choosing a permmap, recheck if self._permmap: self.permmap_editor.show(self._permmap) def apply_permmap(self, perm_map=None): if perm_map: self._permmap = perm_map for index in range(self.AnalysisTabs.count()): tab = self.AnalysisTabs.widget(index) self.log.debug("Updating permmap in tab {0} ({1}: \"{2}\")".format( index, tab, tab.objectName())) tab.perm_map = self._permmap def save_permmap(self): path = str(self._permmap) if self._permmap else "perm_map" filename = QFileDialog.getSaveFileName(self, "Save permission map file", path)[0] if filename: try: self._permmap.save(filename) except Exception as ex: self.log.critical("Failed to save permission map: {0}".format(ex)) self.error_msg.critical(self, "Permission map saving error", str(ex)) # # Analysis tab handling # def choose_analysis(self): if not self._policy: self.error_msg.critical(self, "No open policy", "Cannot start a new analysis. Please open a policy first.") self.select_policy() if self._policy: # this check of self._policy is here in case someone # tries to start an analysis with no policy open, but then # cancels out of the policy file chooser or there is an # error opening the policy file. self.chooser.show(self._policy.mls) def create_new_analysis(self, tabtitle, tabclass): self.tab_counter += 1 counted_name = "{0}: {1}".format(self.tab_counter, tabtitle) newanalysis = tabclass(self, self._policy, self._permmap) newanalysis.setAttribute(Qt.WA_DeleteOnClose) newanalysis.setObjectName(counted_name) index = self.AnalysisTabs.addTab(newanalysis, counted_name) self.AnalysisTabs.setTabToolTip(index, tabtitle) self.AnalysisTabs.setCurrentIndex(index) return index def tab_name_editor(self, index): if index >= 0: tab_area = self.AnalysisTabs.tabBar().tabRect(index) self.tab_editor.move(self.AnalysisTabs.mapToGlobal(tab_area.topLeft())) self.tab_editor.setText(self.AnalysisTabs.tabText(index)) self.tab_editor.selectAll() self.tab_editor.show() self.tab_editor.setFocus() def close_active_tab(self): """Close the active tab. This is called from the context menu.""" index = self.AnalysisTabs.currentIndex() if index >= 0: self.close_tab(index) def rename_active_tab(self): """Rename the active tab.""" index = self.AnalysisTabs.currentIndex() if index >= 0: self.tab_name_editor(index) def close_tab(self, index): """Close a tab specified by index.""" widget = self.AnalysisTabs.widget(index) widget.close() self.AnalysisTabs.removeTab(index) def rename_tab(self): # this should never be negative since the editor is modal index = self.AnalysisTabs.currentIndex() tab = self.AnalysisTabs.widget(index) title = self.tab_editor.text() self.tab_editor.hide() self.AnalysisTabs.setTabText(index, title) tab.setObjectName(title) # # Workspace actions # def toggle_workspace_actions(self, index=-1): """ Enable or disable workspace actions depending on how many tabs are open and if a policy is open. This is a slot for the QTabWidget.currentChanged() signal, though index is ignored. """ open_tabs = self.AnalysisTabs.count() > 0 open_policy = self._policy is not None self.log.debug("{0} actions requiring an open policy.". format("Enabling" if open_policy else "Disabling")) self.log.debug("{0} actions requiring open tabs.". format("Enabling" if open_tabs else "Disabling")) self.save_settings_action.setEnabled(open_tabs) self.save_workspace_action.setEnabled(open_tabs) self.new_analysis.setEnabled(open_policy) self.new_from_settings_action.setEnabled(open_policy) self.load_settings_action.setEnabled(open_tabs) def _get_settings(self, index=None): """Return a dictionary with the settings of the tab at the specified index.""" if index is None: index = self.AnalysisTabs.currentIndex() assert index >= 0, "Tab index is negative in _get_settings. This is an SETools bug." tab = self.AnalysisTabs.widget(index) settings = tab.save() # add the tab info to the settings. settings["__title__"] = self.AnalysisTabs.tabText(index) settings["__tab__"] = type(tab).__name__ return settings def _put_settings(self, settings, index=None): """Load the settings into the specified tab.""" if index is None: index = self.AnalysisTabs.currentIndex() assert index >= 0, "Tab index is negative in _put_settings. This is an SETools bug." tab = self.AnalysisTabs.widget(index) if settings["__tab__"] != type(tab).__name__: raise TypeError("The current tab ({0}) does not match the tab in the settings file " "({1}).".format(type(tab).__name__, settings["__tab__"])) try: self.AnalysisTabs.setTabText(index, str(settings["__title__"])) except KeyError: self.log.warning("Settings file does not have a title setting.") tab.load(settings) def load_settings(self, new=False): filename = QFileDialog.getOpenFileName(self, "Open settings file", ".", "Apol Tab Settings File (*.apolt);;" "All Files (*)")[0] if not filename: return try: with open(filename, "r") as fd: settings = json.load(fd) except ValueError as ex: self.log.critical("Invalid settings file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load settings", "Invalid settings file: \"{0}\"".format(filename)) return except OSError as ex: self.log.critical("Unable to load settings file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to load settings", "Failed to load \"{0.filename}\": {0.strerror}".format(ex)) return except Exception as ex: self.log.critical("Unable to load settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load settings", str(ex)) return self.log.info("Loading analysis settings from \"{0}\"".format(filename)) if new: try: tabclass = TAB_REGISTRY[settings["__tab__"]] except KeyError: self.log.critical("Missing analysis type in \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load settings", "The type of analysis is missing in the settings file.") return # The tab title will be set by _put_settings. index = self.create_new_analysis("Tab", tabclass) else: index = None try: self._put_settings(settings, index) except Exception as ex: self.log.critical("Error loading settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load settings", "Error loading settings file \"{0}\":\n\n{1}". format(filename, ex)) else: self.log.info("Successfully loaded analysis settings from \"{0}\"".format(filename)) def new_analysis_from_config(self): self.load_settings(new=True) def save_settings(self): try: settings = self._get_settings() except TabFieldError as ex: self.log.critical("Errors in the query prevent saving the settings. {0}".format(ex)) self.error_msg.critical(self, "Unable to save settings", "Please resolve errors in the tab before saving the settings." ) return filename = QFileDialog.getSaveFileName(self, "Save analysis tab settings", "analysis.apolt", "Apol Tab Settings File (*.apolt);;" "All Files (*)")[0] if not filename: return try: with open(filename, "w") as fd: json.dump(settings, fd, indent=1) except OSError as ex: self.log.critical("Unable to save settings file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to save settings", "Failed to save \"{0.filename}\": {0.strerror}".format(ex)) except Exception as ex: self.log.critical("Unable to save settings file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to save settings", str(ex)) else: self.log.info("Successfully saved settings file \"{0}\"".format(filename)) def load_workspace(self): # 1. if number of tabs > 0, check if we really want to do this if self.AnalysisTabs.count() > 0: reply = QMessageBox.question( self, "Continue?", "Loading a workspace will close all existing analyses. Continue?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return # 2. try to load the workspace file, if we fail, bail filename = QFileDialog.getOpenFileName(self, "Open workspace file", ".", "Apol Workspace Files (*.apolw);;" "All Files (*)")[0] if not filename: return try: with open(filename, "r") as fd: workspace = json.load(fd) except ValueError as ex: self.log.critical("Invalid workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load workspace", "Invalid workspace file: \"{0}\"".format(filename)) return except OSError as ex: self.log.critical("Unable to load workspace file \"{0.filename}\": {0.strerror}". format(ex)) self.error_msg.critical(self, "Failed to load workspace", "Failed to load \"{0.filename}\": {0.strerror}".format(ex)) return except Exception as ex: self.log.critical("Unable to load workspace file \"{0}\": {1}".format(filename, ex)) self.error_msg.critical(self, "Failed to load workspace", str(ex)) return # 3. close all tabs. Explicitly do this to avoid the question # about closing the policy with tabs open. self.AnalysisTabs.clear() # 4. close policy self.close_policy() # 5. try to open the specified policy, if we fail, bail. Note: # handling exceptions from the policy load is done inside # the load_policy function, so only the KeyError needs to be caught here try: self.load_policy(workspace["__policy__"]) except KeyError: self.log.critical("Missing policy in workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Missing policy in workspace file \"{0}\"". format(filename)) if self._policy is None: self.log.critical("The policy could not be loaded in workspace file \"{0}\"". format(filename)) self.error_msg.critical(self, "The policy could not be loaded in workspace file \"{0}\"" ". Aborting workspace load.".format(filename)) return # 6. try to open the specified perm map, if we fail, # tell the user we will continue with the default map; load the default map # Note: handling exceptions from the map load is done inside # the load_permmap function, so only the KeyError needs to be caught here try: self.load_permmap(workspace["__permmap__"]) except KeyError: self.log.warning("Missing permission map in workspace file \"{0}\"".format(filename)) self.error_msg.warning(self, "Missing permission map setting.", "Missing permission map in workspace file \"{0}\"". format(filename)) if self._permmap is None: self.error_msg.information(self, "Loading default permission map.", "The default permisison map will be loaded.") self.load_permmap() # 7. try to open all tabs and apply settings. Record any errors try: tab_list = list(workspace["__tabs__"]) except KeyError: self.log.critical("Missing tab list in workspace file \"{0}\"".format(filename)) self.error_msg.critical(self, "Failed to load workspace", "The workspace file is missing the tab list. Aborting.") return except TypeError: self.log.critical("Invalid tab list in workspace file.") self.error_msg.critical(self, "Failed to load workspace", "The tab count is invalid. Aborting.") return loading_errors = [] for i, settings in enumerate(tab_list): try: tabclass = TAB_REGISTRY[settings["__tab__"]] except KeyError: error_str = "Missing analysis type for tab {0}. Skipping this tab.".format(i) self.log.error(error_str) loading_errors.append(error_str) continue # The tab title will be set by _put_settings. index = self.create_new_analysis("Tab", tabclass) try: self._put_settings(settings, index) except Exception as ex: error_str = "Error loading settings for tab {0}: {1}".format(i, ex) self.log.error(error_str) loading_errors.append(error_str) self.log.info("Completed loading workspace from \"{0}\"".format(filename)) # 8. if there are any errors, open a dialog with the # complete list of tab errors if loading_errors: self.error_msg.warning(self, "Errors while loading workspace:", "There were errors while loading the workspace:\n\n{0}". format("\n\n".join(loading_errors))) def save_workspace(self): workspace = {} save_errors = [] workspace["__policy__"] = os.path.abspath(str(self._policy)) workspace["__permmap__"] = os.path.abspath(str(self._permmap)) workspace["__tabs__"] = [] for index in range(self.AnalysisTabs.count()): tab = self.AnalysisTabs.widget(index) try: settings = tab.save() except TabFieldError as ex: tab_name = self.AnalysisTabs.tabText(index) save_errors.append(tab_name) self.log.error("Error: tab \"{0}\": {1}".format(tab_name, str(ex))) else: # add the tab info to the settings. settings["__title__"] = self.AnalysisTabs.tabText(index) settings["__tab__"] = type(tab).__name__ workspace["__tabs__"].append(settings) if save_errors: self.log.critical("Errors in tabs prevent saving the workspace.") self.error_msg.critical(self, "Unable to save workspace", "Please resolve errors in the following tabs before saving the" " workspace:\n\n{0}".format("\n".join(save_errors))) return filename = QFileDialog.getSaveFileName(self, "Save analysis workspace", "workspace.apolw", "Apol Workspace Files (*.apolw);;" "All Files (*)")[0] if not filename: return with open(filename, "w") as fd: json.dump(workspace, fd, indent=1) # # Edit actions # def copy(self): """Copy text from the currently-focused widget.""" with suppress(AttributeError): QApplication.instance().focusWidget().copy() def cut(self): """Cut text from the currently-focused widget.""" with suppress(AttributeError): QApplication.instance().focusWidget().cut() def paste(self): """Paste text into the currently-focused widget.""" with suppress(AttributeError): QApplication.instance().focusWidget().paste() # # Help actions # def about_apol(self): QMessageBox.about(self, "About Apol", "Version {0}
" "Apol is a graphical SELinux policy analysis tool and part of " "" "SETools.

" "Copyright (C) 2015-2016, Tresys Technology

" "Copyright (C) 2016-2019, Chris PeBenito ". format(__version__)) def apol_help(self): """Open the main help window.""" if self.help_process.state() != QProcess.NotRunning: return distro = pkg_resources.get_distribution("setools") helpfile = "{0}/setoolsgui/apol/apol.qhc".format(distro.location) self.log.debug("Starting assistant with help file {0}".format(helpfile)) self.help_process.start(self.config.assistant, ["-collectionFile", helpfile, "-showUrl", "qthelp://com.github.selinuxproject.setools/doc/index.html", "-show", "contents", "-enableRemoteControl"]) @pyqtSlot(QProcess.ProcessError) def help_failed(self, error): """Starting assistant failed.""" if error != QProcess.FailedToStart: return self.log.error("Failed to start Qt assistant {}.".format(self.config.assistant)) self._find_assistant() def _find_assistant(self): """Try to find qt assistant in a few standard locations.""" for name in POSSIBLE_ASSISTANT: self.log.debug("Trying assistant {}".format(name)) filename = shutil.which(name, mode=os.F_OK | os.X_OK, path=BIN_SEARCH_PATHS) if filename: self.log.debug("Assistant {} is available and executable.".format(filename)) break else: reply = QMessageBox.question( self, "Qt Assistant Package Installed?", "Failed to start QT Assistant program {}. " "This is typically in the assistant or qt5-assistant package. " "Choose location of Qt Assistant executable?".format( self.config.assistant), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return filename = QFileDialog.getOpenFileName(self, "Location of qt-assistant executable", "/usr/bin", "All Files (*)")[0] self.log.debug("User chose assistant {}.".format(filename)) if filename: self.log.debug("Updating config with assistant {}".format(filename)) self.config.assistant = filename self.config.save() self.apol_help() @pyqtSlot(str) def set_help(self, location): """Set the help window to the specified document.""" if self.help_process.state() == QProcess.NotStarted: self.apol_help() if not self.help_process.waitForStarted(): self.log.warning("Timed out waiting for Qt assistant to start.") return elif self.help_process.state() == QProcess.Starting: if not self.help_process.waitForStarted(): self.log.warning("Timed out waiting for Qt assistant to start.") return self.help_process.write("setSource qthelp://com.github.selinuxproject.setools/doc/{0}\n". format(location)) setools-4.4.0/setoolsgui/apol/mlsrulequery.py000066400000000000000000000247061402045477700215050ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import MLSRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsrulemodel import MLSRuleTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class MLSRuleQueryTab(AnalysisTab): """An MLS rule query.""" section = AnalysisSection.Rules tab_title = "MLS Rules" mlsonly = True def __init__(self, parent, policy, perm_map): super(MLSRuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = MLSRuleQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.mlsrulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/mlsrulequery.ui") # set up source/target autocompletion typeattr_completion_list = [str(t) for t in self.policy.types()] typeattr_completion_list.extend(str(a) for a in self.policy.typeattributes()) typeattr_completer_model = QStringListModel(self) typeattr_completer_model.setStringList(sorted(typeattr_completion_list)) self.typeattr_completion = QCompleter() self.typeattr_completion.setModel(typeattr_completer_model) self.source.setCompleter(self.typeattr_completion) self.target.setCompleter(self.typeattr_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # set up results self.table_results_model = MLSRuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(1, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.mlsrulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.default_range.textEdited.connect(self.clear_default_error) self.default_range.editingFinished.connect(self.set_default_range) # # Ruletype criteria # def _set_ruletypes(self, value): self.range_transition.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source type/attribute of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source type/attribute error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target type/attribute of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/attribute error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_range, "Match the default type the rule.") def set_default_range(self): try: self.query.default = self.default_range.text() except Exception as ex: self.log.error("Default range error: {0}".format(ex)) self.set_criteria_error(self.default_range, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "range_transition", "source_indirect", "source_regex", "target_indirect", "target_regex"]) save_lineedits(self, settings, ["source", "target", "default_range"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "range_transition", "source_indirect", "source_regex", "target_indirect", "target_regex"]) load_lineedits(self, settings, ["source", "target", "default_range"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.ruletype = ['range_transition'] self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} MLS rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/mlsrulequery.ui000066400000000000000000000575361402045477700215010ustar00rootroot00000000000000 MLSRuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Qt::Horizontal 40 20 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 0 16777215 20 12 75 true Multi-Level Security (MLS) Rule Query 0 1 0 80 Optionally enter notes here about the query. Enter notes here. 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Type/Attribute 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 false Select All Qt::Horizontal 40 20 false Clear false false Range_transition true 16777215 100 Source Type/Attribute 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 Use regular expressions to match the source type/attribute. Regex If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection QDialogButtonBox::Apply Default Range 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 ruletype_criteria source_criteria target_criteria class_criteria buttonBox default_criteria SEToolsTableView QTableView

setoolsgui/tableview.h
criteria_expander notes_expander range_transition clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class default_range results_frame table_results raw_results notes clear_class clicked() tclass clearSelection() 299 312 147 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 222 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756 setools-4.4.0/setoolsgui/apol/netifconquery.py000066400000000000000000000271761402045477700216330ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import NetifconQuery from ..logtosignal import LogHandlerToSignal from ..netifconmodel import NetifconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class NetifconQueryTab(AnalysisTab): """A netifcon query.""" section = AnalysisSection.Labeling tab_title = "Network Interface Contexts" mlsonly = False def __init__(self, parent, policy, perm_map): super(NetifconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = NetifconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.netifconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/netifconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = NetifconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.netifconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_name_regex(self.name_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the device name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Device name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "user", "role", "type_", "range_"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} netifcon statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/netifconquery.ui000066400000000000000000000533171402045477700216140ustar00rootroot00000000000000 NetifconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Network Interface Contexts 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Device Context Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply 16777215 100 Device Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Device Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Device Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Device Name Use regular expressions to match the device name. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox name_criteria Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander name name_regex user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/nodeconquery.py000066400000000000000000000300401402045477700214330ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import NodeconQuery, NodeconIPVersion from ..logtosignal import LogHandlerToSignal from ..nodeconmodel import NodeconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \ save_checkboxes, save_lineedits, save_textedits, save_comboboxes class NodeconQueryTab(AnalysisTab): """An nodecon query.""" section = AnalysisSection.Labeling tab_title = "Network Node Contexts" mlsonly = False def __init__(self, parent, policy, perm_map): super(NodeconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = NodeconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.nodeconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/nodeconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup IP version # item 0 is empty string (in the .ui file) self.ip_version.insertItem(1, "IPv4", NodeconIPVersion.ipv4) self.ip_version.insertItem(2, "IPv6", NodeconIPVersion.ipv6) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_network_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # set up results self.table_results_model = NodeconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.nodeconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.network.textEdited.connect(self.clear_network_error) self.network.editingFinished.connect(self.set_network) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Network criteria # def clear_network_error(self): self.clear_criteria_error(self.network, "Match the network.") def set_network(self): try: self.query.network = self.network.text() except Exception as ex: self.log.error("Network error: {0}".format(ex)) self.set_criteria_error(self.network, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "network_exact", "network_overlap", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["network", "user", "role", "type_", "range_"]) save_comboboxes(self, settings, ["ip_version"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "network_exact", "network_overlap", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["network", "user", "role", "type_", "range_"]) load_comboboxes(self, settings, ["ip_version"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.network_overlap = self.network_overlap.isChecked() self.query.ip_version = self.ip_version.currentData(Qt.UserRole) self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} nodecon statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/nodeconquery.ui000066400000000000000000000574061402045477700214370ustar00rootroot00000000000000 NodeconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Network Node Contexts Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 100 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 250 16777215 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Network 0 0 150 0 250 16777215 e.g. 192.168.1.0/24 Match the network if the criteria overlaps the nodecon's network range. Overlap true Match the network if the criteria is equal to the nodecon's network range. Equal false Qt::Horizontal 40 20 IP Version Qt::Horizontal 40 20 Match the IP version of the nodecon. role_criteria type_criteria user_critera range_criteria buttonBox ip_version_criteria network_criteria SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander network network_exact network_overlap ip_version user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/objclassquery.py000066400000000000000000000214541402045477700216170ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import ObjClassQuery from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..objclassmodel import ObjClassTableModel, class_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class ObjClassQueryTab(AnalysisTab): """ObjClass browser and query tab.""" section = AnalysisSection.Components tab_title = "Object Classes" mlsonly = False def __init__(self, parent, policy, perm_map): super(ObjClassQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = ObjClassQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.objclassquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/objclassquery.ui") # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(c for c in self.policy.classes()) self.classes.setModel(self.class_model) # populate commons list self.common_model = SEToolsListModel(self) self.common_model.item_list = sorted(c for c in self.policy.commons()) self.common.setModel(self.common_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # set up results self.table_results_model = ObjClassTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.objclassquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.classes.doubleClicked.connect(self.get_detail) self.classes.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.common.selectionModel().selectionChanged.connect(self.set_common) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.buttonBox.clicked.connect(self.run) # # Class browser # def get_detail(self): # .ui is set for single item selection. index = self.classes.selectedIndexes()[0] item = self.class_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) class_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the object class name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Object class name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Common criteria # def set_common(self): for index in self.common.selectionModel().selectedIndexes(): self.query.common = self.common_model.data(index, Qt.UserRole) break else: self.query.common = None # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["common", "perms"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "perms_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["common", "perms"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.perms_equal = self.perms_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} object class(es) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/objclassquery.ui000066400000000000000000000456501402045477700216100ustar00rootroot00000000000000 ObjClassQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Object Classes 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Class Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Class Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex 16777215 120 Common 6 6 6 6 3 250 16777215 A matching class will inherit the selected common. QAbstractItemView::NoEditTriggers Clear Qt::Horizontal 40 20 Permission Set 0 0 250 16777215 A matching class will have the selected permissions. QAbstractItemView::ExtendedSelection Clear A matching class will have a permission set equal to the selected permissions. Equal Qt::Horizontal 40 20 Invert Qt::Vertical 20 40 QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander classes name name_regex common clear_common perms clear_perms invert_perms perms_equal results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226 clear_perms clicked() perms clearSelection() 592 216 442 276 clear_common clicked() common clearSelection() 701 126 595 127
setools-4.4.0/setoolsgui/apol/permmap_editor.ui000066400000000000000000000070711402045477700217240ustar00rootroot00000000000000 PermissionMapEditor_ui 0 0 759 451 Dialog 11 75 true Permission Map Editor QFrame::StyledPanel QFrame::Raised Include All Permissions 250 16777215 Exclude All Permissions true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 463 331 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok classes scrollArea enable_all disable_all buttonBox accepted() PermissionMapEditor_ui accept() 248 254 157 274 buttonBox rejected() PermissionMapEditor_ui reject() 316 260 286 274 setools-4.4.0/setoolsgui/apol/permmapedit.py000066400000000000000000000201461402045477700212350ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging import copy from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt from PyQt5.QtGui import QPalette from PyQt5.QtWidgets import QDialog, QFrame, QWidget from ..models import SEToolsListModel from ..widget import SEToolsWidget class PermissionMapEditor(SEToolsWidget, QDialog): """ A permission map editor. This dialog has two versions, one for editing the weight/direction and another for including or excluding permissions in an analysis. Parameters: parent The parent Qt widget edit (bool) If true, the dialog will take the editor behavior. If False, the dialog will take the enable/disable permission behavior. """ class_toggle = pyqtSignal(bool) def __init__(self, parent, edit): super(PermissionMapEditor, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.edit = edit self.setupUi() def setupUi(self): self.load_ui("apol/permmap_editor.ui") # set up class list self.class_model = SEToolsListModel(self) self.classes.setModel(self.class_model) # permission widgets self.widgets = [] # set up editor mode self.enable_all.setHidden(self.edit) self.disable_all.setHidden(self.edit) # connect signals self.classes.selectionModel().selectionChanged.connect(self.class_selected) self.enable_all.clicked.connect(self.enable_all_perms) self.disable_all.clicked.connect(self.disable_all_perms) def show(self, perm_map): # keep an internal copy because the map is mutable # and this dialog may be canceled after some edits. self.perm_map = copy.deepcopy(perm_map) self.class_model.item_list = sorted(perm_map.classes()) # clear class selection and mappings # since this widget will typically # be reused. self.classes.clearSelection() self._clear_mappings() self.enable_all.setToolTip(None) self.disable_all.setToolTip(None) if self.edit: self.setWindowTitle("{0} - Permission Map Editor - apol".format(self.perm_map)) else: self.setWindowTitle("{0} - Permission Map Viewer - apol".format(self.perm_map)) super(PermissionMapEditor, self).show() def accept(self): self.parent.apply_permmap(self.perm_map) super(PermissionMapEditor, self).accept() def class_selected(self): # the .ui is set to 1 selection for index in self.classes.selectionModel().selectedIndexes(): class_name = self.class_model.data(index, Qt.DisplayRole) self.log.debug("Setting class to {0}".format(class_name)) self.enable_all.setToolTip("Include all permissions in the {0} class.".format(class_name)) self.disable_all.setToolTip("Exclude all permissions in the {0} class.".format(class_name)) self._clear_mappings() # populate new mappings for perm in sorted(self.perm_map.perms(class_name)): # create permission mapping mapping = PermissionMapping(self, perm, self.edit) mapping.setAttribute(Qt.WA_DeleteOnClose) self.class_toggle.connect(mapping.enabled.setChecked) self.perm_mappings.addWidget(mapping) self.widgets.append(mapping) # add horizonal line line = QFrame(self) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.perm_mappings.addWidget(line) self.widgets.append(line) def enable_all_perms(self): self.class_toggle.emit(True) def disable_all_perms(self): self.class_toggle.emit(False) # # Internal functions # def _clear_mappings(self): # delete current mappings for mapping in self.widgets: mapping.close() self.widgets.clear() index_to_setting = ["r", "w", "b", "n"] index_to_word = ["Read", "Write", "Both", "None"] setting_to_index = {"r": 0, "w": 1, "b": 2, "n": 3} class PermissionMapping(SEToolsWidget, QWidget): """ A widget representing mapping for a particular permission. This dialog has two versions, one for editing the weight/direction and another for including or excluding permissions in an analysis. Parameters: parent The parent Qt widget edit (bool) If true, the widget will take the editor behavior. If False, the dialog will take the enable/disable permission behavior. """ def __init__(self, parent, mapping, edit): super(PermissionMapping, self).__init__(parent) self.log = logging.getLogger(__name__) self.parent = parent self.mapping = mapping self.edit = edit self.setupUi() def setupUi(self): self.load_ui("apol/permmapping.ui") self.permission.setText(str(self.mapping.perm)) self.weight.setValue(self.mapping.weight) self.enabled.setChecked(self.mapping.enabled) if self.edit: self.weight.setToolTip("Set the information flow weight of {0}".format( self.mapping.perm)) self.direction.setToolTip("Set the information flow direction of {0}".format( self.mapping.perm)) else: self.enabled.setToolTip("Include or exclude {0} from the analysis.".format( self.mapping.perm)) self.weight.setEnabled(self.edit) self.direction.setEnabled(self.edit) self.enabled.setHidden(self.edit) # setup color palettes for direction self.orig_palette = self.direction.palette() self.error_palette = self.direction.palette() self.error_palette.setColor(QPalette.Button, Qt.red) self.error_palette.setColor(QPalette.ButtonText, Qt.white) # setup direction self.direction.insertItems(0, index_to_word) if self.mapping.direction == 'u': # Temporarily add unmapped value to items self.direction.insertItem(len(index_to_word), "Unmapped") self.direction.setCurrentText("Unmapped") self.direction.setPalette(self.error_palette) self.unmapped = True else: self.direction.setCurrentIndex(setting_to_index[self.mapping.direction]) self.unmapped = False # connect signals self.direction.currentIndexChanged.connect(self.set_direction) self.weight.valueChanged.connect(self.set_weight) self.enabled.toggled.connect(self.set_enabled) def set_direction(self, value): if self.unmapped: if value == "Unmapped": return # Remove unmapped item if setting the mapping. self.direction.removeItem(len(index_to_word)) self.direction.setPalette(self.orig_palette) self.unmapped = False dir_ = index_to_setting[value] self.log.debug("Setting {0.class_}:{0.perm} direction to {1}".format(self.mapping, dir_)) self.mapping.direction = dir_ def set_weight(self, value): self.log.debug("Setting {0.class_}:{0.perm} weight to {1}".format(self.mapping, value)) self.mapping.weight = int(value) def set_enabled(self, value): self.log.debug("Setting {0.class_}:{0.perm} enabled to {1}".format(self.mapping, value)) self.mapping.enabled = value setools-4.4.0/setoolsgui/apol/permmapping.ui000066400000000000000000000022001402045477700212210ustar00rootroot00000000000000 PermMapping_ui 0 0 457 41 Form TextLabel 1 10 Include setools-4.4.0/setoolsgui/apol/portconquery.py000066400000000000000000000314171402045477700215030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import PortconQuery, PortconProtocol from ..logtosignal import LogHandlerToSignal from ..portconmodel import PortconTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, load_comboboxes, \ save_checkboxes, save_lineedits, save_textedits, save_comboboxes class PortconQueryTab(AnalysisTab): """An portcon query.""" section = AnalysisSection.Labeling tab_title = "Network Port Contexts" mlsonly = False def __init__(self, parent, policy, perm_map): super(PortconQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = PortconQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.portconquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/portconquery.ui") # set up user autocompletion user_completion_list = [str(u) for u in self.policy.users()] user_completer_model = QStringListModel(self) user_completer_model.setStringList(sorted(user_completion_list)) self.user_completion = QCompleter() self.user_completion.setModel(user_completer_model) self.user.setCompleter(self.user_completion) # set up role autocompletion role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.role.setCompleter(self.role_completion) # set up type autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.type_.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.type_.palette() self.error_palette = self.type_.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_ports_error() self.clear_user_error() self.clear_type_error() self.clear_role_error() self.clear_range_error() # populate protocol list. This has empty string as # the first item in the .ui file: for i, e in enumerate(PortconProtocol, start=1): self.protocol.insertItem(i, e.name.upper(), e) # set up results self.table_results_model = PortconTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.portconquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # Range criteria is available only if policy is MLS if not self.policy.mls: self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # connect signals self.buttonBox.clicked.connect(self.run) self.ports.textEdited.connect(self.clear_ports_error) self.ports.editingFinished.connect(self.set_ports) self.user.textEdited.connect(self.clear_user_error) self.user.editingFinished.connect(self.set_user) self.user_regex.toggled.connect(self.set_user_regex) self.role.textEdited.connect(self.clear_role_error) self.role.editingFinished.connect(self.set_role) self.role_regex.toggled.connect(self.set_role_regex) self.type_.textEdited.connect(self.clear_type_error) self.type_.editingFinished.connect(self.set_type) self.type_regex.toggled.connect(self.set_type_regex) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) # # Ports criteria # def clear_ports_error(self): self.clear_criteria_error(self.ports, "Match the ports.") def set_ports(self): try: pending_ports = self.ports.text() if pending_ports: try: ports = [int(i) for i in pending_ports.split("-")] except ValueError as ex: raise ValueError("Enter a port number or range, e.g. 22 or 6000-6020") from ex if len(ports) == 2: self.query.ports = ports elif len(ports) == 1: self.query.ports = (ports[0], ports[0]) else: raise ValueError("Enter a port number or range, e.g. 22 or 6000-6020") else: self.query.ports = (0, 0) except Exception as ex: self.log.error("Ports error: {0}".format(ex)) self.set_criteria_error(self.ports, ex) # # User criteria # def clear_user_error(self): self.clear_criteria_error(self.user, "Match the user of the context.") def set_user(self): try: self.query.user = self.user.text() except Exception as ex: self.log.error("Context user error: {0}".format(ex)) self.set_criteria_error(self.user, ex) def set_user_regex(self, state): self.log.debug("Setting user_regex {0}".format(state)) self.query.user_regex = state self.clear_user_error() self.set_user() # # Role criteria # def clear_role_error(self): self.clear_criteria_error(self.role, "Match the role of the context.") def set_role(self): try: self.query.role = self.role.text() except Exception as ex: self.log.error("Context role error: {0}".format(ex)) self.set_criteria_error(self.role, ex) def set_role_regex(self, state): self.log.debug("Setting role_regex {0}".format(state)) self.query.role_regex = state self.clear_role_error() self.set_role() # # Type criteria # def clear_type_error(self): self.clear_criteria_error(self.type_, "Match the type of the context.") def set_type(self): try: self.query.type_ = self.type_.text() except Exception as ex: self.log.error("Context type error: {0}".format(ex)) self.set_criteria_error(self.type_, ex) def set_type_regex(self, state): self.log.debug("Setting type_regex {0}".format(state)) self.query.type_regex = state self.clear_type_error() self.set_type() # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the range of the context.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Context range error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "ports_exact", "ports_overlap", "ports_subset", "ports_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["ports", "user", "role", "type_", "range_"]) save_comboboxes(self, settings, ["protocol"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "ports_exact", "ports_overlap", "ports_subset", "ports_superset", "user_regex", "role_regex", "type_regex", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["ports", "user", "role", "type_", "range_"]) load_comboboxes(self, settings, ["protocol"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.ports_overlap = self.ports_overlap.isChecked() self.query.ports_subset = self.ports_subset.isChecked() self.query.ports_superset = self.ports_superset.isChecked() self.query.protocol = self.protocol.currentData(Qt.UserRole) self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} portcon statement(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/portconquery.ui000066400000000000000000000604631402045477700214730ustar00rootroot00000000000000 PortconQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Network Port Contexts Show: Qt::Horizontal 40 20 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 16777215 16777215 QFrame::StyledPanel QFrame::Raised 16777215 16777215 Context MLS Range 6 6 6 6 3 Match the context's range if the criteria is equal to the context's range. Equal true Match the context's range if the criteria overlaps the context's range. Overlap Match the context's range if the criteria is a subset of the context's range. Subset Match the context's range if the criteria is a superset to the context's range. Superset 0 0 150 20 250 16777215 Qt::Horizontal QSizePolicy::Preferred 40 20 QDialogButtonBox::Apply 16777215 100 Context Type 6 6 6 6 3 Use regular expressions to match the context's type. Regex 0 0 150 0 250 16777215 Qt::Horizontal 40 20 16777215 100 Context Role 6 6 6 6 3 0 0 150 0 250 16777215 true Use regular expressions to match the context's role. Regex Qt::Horizontal 40 20 Context User 0 0 150 0 Use regular expressions to match the context's user. Regex Qt::Horizontal 40 20 Port/Port Range 0 0 150 0 250 16777215 e.g. 80 or 6000-6010 Match the port range if the criteria is a superset to the portcon's port range. Superset Match the port range if the criteria overlaps the portcon's port range. Overlap true Match the port range if the criteria is equal to the portcon's port range. Equal false Match the port range if the criteria is a subset of the portcon's port range. Subset Qt::Horizontal 40 20 Protocol Qt::Horizontal 40 20 role_criteria type_criteria user_critera range_criteria buttonBox protocol_criteria port_criteria SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander ports ports_exact ports_overlap ports_subset ports_superset protocol user user_regex role role_regex type_ type_regex range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/queryupdater.py000066400000000000000000000037051402045477700214620ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import pyqtSignal, QObject, QThread class QueryResultsUpdater(QObject): """ Thread for processing basic queries and updating result widgets. Parameters: query The query object model The model for the results Qt signals: finished (int) The update has completed, with the number of results. raw_line (str) A string to be appended to the raw results. """ finished = pyqtSignal(int) raw_line = pyqtSignal(str) def __init__(self, query, model): super(QueryResultsUpdater, self).__init__() self.query = query self.model = model def update(self): """Run the query and update results.""" self.model.beginResetModel() results = [] counter = 0 for counter, item in enumerate(self.query.results(), start=1): results.append(item) self.raw_line.emit(str(item)) if QThread.currentThread().isInterruptionRequested(): break elif not counter % 10: # yield execution every 10 rules QThread.yieldCurrentThread() self.model.resultlist = results self.model.endResetModel() self.finished.emit(counter) setools-4.4.0/setoolsgui/apol/rbacrulequery.py000066400000000000000000000273231402045477700216170ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import RBACRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..rbacrulemodel import RBACRuleTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class RBACRuleQueryTab(AnalysisTab): """A RBAC rule query.""" section = AnalysisSection.Rules tab_title = "RBAC Rules" mlsonly = False def __init__(self, parent, policy, perm_map): super(RBACRuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = RBACRuleQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.rbacrulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/rbacrulequery.ui") # set up role autocompletion (source, default) role_completion_list = [str(r) for r in self.policy.roles()] role_completer_model = QStringListModel(self) role_completer_model.setStringList(sorted(role_completion_list)) self.role_completion = QCompleter() self.role_completion.setModel(role_completer_model) self.source.setCompleter(self.role_completion) self.default_role.setCompleter(self.role_completion) # set up role/type autocompletion (target) roletype_completion_list = [str(r) for r in self.policy.roles()] # roletype_completion_list.extend(str(a) for a in self.policy.roleattributes()) roletype_completion_list.extend(str(t) for t in self.policy.types()) roletype_completion_list.extend(str(a) for a in self.policy.typeattributes()) roletype_completer_model = QStringListModel(self) roletype_completer_model.setStringList(sorted(roletype_completion_list)) self.roletype_completion = QCompleter() self.roletype_completion.setModel(roletype_completer_model) self.target.setCompleter(self.roletype_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # set up results self.table_results_model = RBACRuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.rbacrulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.set_default_regex(self.default_regex.isChecked()) self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.default_role.textEdited.connect(self.clear_default_error) self.default_role.editingFinished.connect(self.set_default_role) self.default_regex.toggled.connect(self.set_default_regex) # # Ruletype criteria # def _set_ruletypes(self, value): self.allow.setChecked(value) self.role_transition.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source role of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source role error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target role/type of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/role error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_role, "Match the default role the rule.") def set_default_role(self): self.query.default_regex = self.default_regex.isChecked() try: self.query.default = self.default_role.text() except Exception as ex: self.log.error("Default role error: {0}".format(ex)) self.set_criteria_error(self.default_role, ex) def set_default_regex(self, state): self.log.debug("Setting default_regex {0}".format(state)) self.query.default_regex = state self.clear_default_error() self.set_default_role() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "role_transition", "source_indirect", "source_regex", "target_indirect", "target_regex", "default_regex"]) save_lineedits(self, settings, ["source", "target", "default_role"]) save_listviews(self, settings, ["tclass"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "role_transition", "source_indirect", "source_regex", "target_indirect", "target_regex", "default_regex"]) load_lineedits(self, settings, ["source", "target", "default_role"]) load_listviews(self, settings, ["tclass"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] for mode in [self.allow, self.role_transition]: if mode.isChecked(): rule_types.append(mode.objectName()) self.query.ruletype = rule_types self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} RBAC rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/rbacrulequery.ui000066400000000000000000000607361402045477700216110ustar00rootroot00000000000000 RBACRuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 Show: 0 1 0 80 Optionally enter notes here about the query. Enter notes here. 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Role/Type 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Qt::Horizontal 40 20 Allow true Clear false Role_transition true 16777215 100 Source Role 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 true Use regular expressions to match the source type/attribute. Regex false If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection QDialogButtonBox::Apply Default Role 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the default type. Regex ruletype_criteria source_criteria target_criteria class_criteria buttonBox default_criteria 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true Show or hide the search criteria (no settings are lost) Criteria true 0 0 16777215 20 12 75 true Role Based Access Control (RBAC) Rule Query Show or hide the notes field (no data is lost) Notes Qt::Horizontal 40 20 SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander allow role_transition clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class default_role default_regex results_frame table_results raw_results notes clear_class clicked() tclass clearSelection() 299 312 147 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 592 16 386 232 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 756
setools-4.4.0/setoolsgui/apol/rolequery.py000066400000000000000000000202631402045477700207550ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import RoleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..rolemodel import RoleTableModel, role_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class RoleQueryTab(AnalysisTab): """Role browser and query tab.""" section = AnalysisSection.Components tab_title = "Roles" mlsonly = False def __init__(self, parent, policy, perm_map): super(RoleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = RoleQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.rolequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/rolequery.ui") # populate role list self.role_model = SEToolsListModel(self) self.role_model.item_list = sorted(r for r in self.policy.roles()) self.roles.setModel(self.role_model) # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # set up results self.table_results_model = RoleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.rolequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.roles.doubleClicked.connect(self.get_detail) self.roles.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.types.selectionModel().selectionChanged.connect(self.set_types) self.invert_types.clicked.connect(self.invert_type_selection) self.buttonBox.clicked.connect(self.run) # # User browser # def get_detail(self): # .ui is set for single item selection. index = self.roles.selectedIndexes()[0] item = self.role_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) role_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the role name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Role name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Type criteria # def set_types(self): selected_types = [] for index in self.types.selectionModel().selectedIndexes(): selected_types.append(self.type_model.data(index, Qt.UserRole)) self.query.types = selected_types def invert_type_selection(self): invert_list_selection(self.types.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["types"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["types"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.types_equal = self.types_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} role(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the types column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/rolequery.ui000066400000000000000000000422321402045477700207420ustar00rootroot00000000000000 RoleQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Roles 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Role Browser 0 0 16777215 16777215 Search Criteria Types 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching role will have a role set equal to the selected types. Equal A matching role will have any of the selected types. Any true 0 0 250 16777215 Match the type set of the role. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Role Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the role's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander roles name name_regex types types_any types_equal clear_types invert_types results_frame table_results raw_results notes clear_types clicked() types clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/sensitivityquery.py000066400000000000000000000166361402045477700224170ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import SensitivityQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsmodel import MLSComponentTableModel, sensitivity_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_textedits, \ save_checkboxes, save_lineedits, save_textedits class SensitivityQueryTab(AnalysisTab): """Sensitivity browser and query tab.""" section = AnalysisSection.Components tab_title = "MLS Sensitivities" mlsonly = True def __init__(self, parent, policy, perm_map): super(SensitivityQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = SensitivityQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.sensitivityquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/sensitivityquery.ui") # populate sensitivity list self.sensitivity_model = SEToolsListModel(self) self.sensitivity_model.item_list = sorted(self.policy.sensitivities()) self.sens.setModel(self.sensitivity_model) # set up results self.table_results_model = MLSComponentTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.sensitivityquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.sens.doubleClicked.connect(self.get_detail) self.sens.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.buttonBox.clicked.connect(self.run) # # Sensitivity browser # def get_detail(self): # .ui is set for single item selection. index = self.sens.selectedIndexes()[0] item = self.sensitivity_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) sensitivity_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the sensitivity name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Sensitivity name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) save_lineedits(self, settings, ["name"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex"]) load_lineedits(self, settings, ["name"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} categories found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/sensitivityquery.ui000066400000000000000000000313121402045477700223700ustar00rootroot00000000000000 SensitivityQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Sensitivities 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Sensitivities Browser 0 0 16777215 16777215 Search Criteria QDialogButtonBox::Apply 16777215 120 Sensitivity Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander sens name name_regex results_frame table_results raw_results notes notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/summary.py000066400000000000000000000143701402045477700204250ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import MLSRuleQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..mlsrulemodel import MLSRuleTableModel from .analysistab import AnalysisSection, AnalysisTab from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_textedits, save_checkboxes, save_textedits class SummaryTab(AnalysisTab): """An SELinux policy summary.""" section = AnalysisSection.General tab_title = "Summary" mlsonly = False def __init__(self, parent, policy, perm_map): super(SummaryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.setupUi(policy) def setupUi(self, p): self.load_ui("apol/summary.ui") # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # Populate policy stats mls = "enabled" if p.mls else "disabled" self.policy_version.setText(str(p.version)) self.mls.setText(mls) self.handle_unknown.setText(p.handle_unknown.name) self.class_count.setText(str(p.class_count)) self.perms_count.setText(str(p.permission_count)) self.type_count.setText(str(p.type_count)) self.attribute_count.setText(str(p.type_attribute_count)) self.user_count.setText(str(p.user_count)) self.role_count.setText(str(p.role_count)) self.bool_count.setText(str(p.boolean_count)) self.allow_count.setText(str(p.allow_count)) self.neverallow_count.setText(str(p.neverallow_count)) self.auditallow_count.setText(str(p.auditallow_count)) self.dontaudit_count.setText(str(p.dontaudit_count)) self.type_transition_count.setText(str(p.type_transition_count)) self.type_change_count.setText(str(p.type_change_count)) self.type_member_count.setText(str(p.type_member_count)) self.role_allow_count.setText(str(p.role_allow_count)) self.role_transition_count.setText(str(p.role_transition_count)) self.constrain_count.setText(str(p.constraint_count)) self.validatetrans_count.setText(str(p.validatetrans_count)) self.permissive_count.setText(str(p.permissives_count)) self.default_count.setText(str(p.default_count)) self.typebounds_count.setText(str(p.typebounds_count)) self.allowxperm_count.setText(str(p.allowxperm_count)) self.neverallowxperm_count.setText(str(p.neverallowxperm_count)) self.auditallowxperm_count.setText(str(p.auditallowxperm_count)) self.dontauditxperm_count.setText(str(p.dontauditxperm_count)) self.ibendportcon_count.setText(str(p.ibendportcon_count)) self.ibpkeycon_count.setText(str(p.ibpkeycon_count)) self.initsid_count.setText(str(p.initialsids_count)) self.fs_use_count.setText(str(p.fs_use_count)) self.genfscon_count.setText(str(p.genfscon_count)) self.portcon_count.setText(str(p.portcon_count)) self.netifcon_count.setText(str(p.netifcon_count)) self.nodecon_count.setText(str(p.nodecon_count)) if p.mls: self.sensitivity_count.setText(str(p.level_count)) self.category_count.setText(str(p.category_count)) self.range_transition_count.setText(str(p.range_transition_count)) self.mlsconstrain_count.setText(str(p.mlsconstraint_count)) self.mlsvalidatetrans_count.setText(str(p.mlsvalidatetrans_count)) else: self.sens_label.setEnabled(False) self.sens_label.setToolTip("MLS is disabled in this policy.") self.cats_label.setEnabled(False) self.cats_label.setToolTip("MLS is disabled in this policy.") self.range_trans_label.setEnabled(False) self.range_trans_label.setToolTip("MLS is disabled in this policy.") self.mlsconstrain_label.setEnabled(False) self.mlsconstrain_label.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans_label.setEnabled(False) self.mlsvalidatetrans_label.setToolTip("MLS is disabled in this policy.") self.sensitivity_count.setEnabled(False) self.sensitivity_count.setToolTip("MLS is disabled in this policy.") self.category_count.setEnabled(False) self.category_count.setToolTip("MLS is disabled in this policy.") self.range_transition_count.setEnabled(False) self.range_transition_count.setToolTip("MLS is disabled in this policy.") self.mlsconstrain_count.setEnabled(False) self.mlsconstrain_count.setToolTip("MLS is disabled in this policy.") self.mlsvalidatetrans_count.setEnabled(False) self.mlsvalidatetrans_count.setToolTip("MLS is disabled in this policy.") # Fill policy capabilities list self.polcaps.addItems([str(c) for c in p.polcaps()]) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" settings = {} save_checkboxes(self, settings, ["notes_expander"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["notes_expander"]) load_textedits(self, settings, ["notes"]) setools-4.4.0/setoolsgui/apol/summary.ui000066400000000000000000000716031402045477700204140ustar00rootroot00000000000000 SummaryTab 0 0 774 749 QAbstractScrollArea::AdjustToContents true 0 0 772 747 0 0 6 6 6 6 3 0 0 16777215 20 12 75 true SELinux Policy Summary Policy Properties 75 true Policy Version: 0 75 true Unknown Permissions: 0 75 true MLS: 0 0 0 200 60 true 75 true Policy Capabilities: 0 0 Show or hide the notes field (no data is lost) Notes Rule Counts 75 true allow: 75 true allowxperm: 75 true auditallow: 75 true auditallowxperm: 75 true neverallow: 75 true neverallowxperm: 75 true dontaudit: 75 true dontauditxperm: 75 true type_transition: 75 true type_member: 75 true type_change: 0 0 0 0 0 0 0 0 0 0 0 75 true role_transition: 75 true allow (role): 75 true range_transition: 0 0 0 Component Counts 75 true Classes: 0 75 true Permissions: 75 true Types: 0 0 75 true Attributes: 0 75 true Roles: 75 true Users: 75 true Booleans: 75 true Sensitivities: 75 true Categories: 0 0 0 0 0 Constraint Counts 75 true constrain: 0 75 true validatetrans: 0 75 true mlsconstrain: 0 75 true mlsvalidatetrans: 0 Other 75 true Permissive Types: 0 75 true Defaults: 0 75 true Typebounds: 0 Labeling Counts 75 true Ibendportcons: 0 75 true Ibpkeycons: 0 75 true Initial SIDs: 0 75 true fs_use_*: 0 75 true Genfscon: 0 75 true Portcon: 0 75 true Netifcon: 0 75 true Nodecon: 0 0 0 0 80 Optionally enter notes here about the query. Enter notes here. 0 0 Show: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter notes_expander polcaps notes notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776 setools-4.4.0/setoolsgui/apol/terulequery.py000066400000000000000000000440701402045477700213160ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TERuleQuery, xperm_str_to_tuple_ranges from ..logtosignal import LogHandlerToSignal from ..models import PermListModel, SEToolsListModel, invert_list_selection from ..terulemodel import TERuleTableModel from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TERuleQueryTab(AnalysisTab): """A Type Enforcement rule query.""" section = AnalysisSection.Rules tab_title = "TE Rules" mlsonly = False def __init__(self, parent, policy, perm_map): super(TERuleQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TERuleQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.terulequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/terulequery.ui") # set up source/target autocompletion typeattr_completion_list = [str(t) for t in self.policy.types()] typeattr_completion_list.extend(str(a) for a in self.policy.typeattributes()) typeattr_completer_model = QStringListModel(self) typeattr_completer_model.setStringList(sorted(typeattr_completion_list)) self.typeattr_completion = QCompleter() self.typeattr_completion.setModel(typeattr_completer_model) self.source.setCompleter(self.typeattr_completion) self.target.setCompleter(self.typeattr_completion) # set up default autocompletion type_completion_list = [str(t) for t in self.policy.types()] type_completer_model = QStringListModel(self) type_completer_model.setStringList(sorted(type_completion_list)) self.type_completion = QCompleter() self.type_completion.setModel(type_completer_model) self.default_type.setCompleter(self.type_completion) # setup indications of errors on source/target/default self.errors = set() self.orig_palette = self.source.palette() self.error_palette = self.source.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_source_error() self.clear_target_error() self.clear_default_error() self.clear_xperm_error() # populate class list self.class_model = SEToolsListModel(self) self.class_model.item_list = sorted(self.policy.classes()) self.tclass.setModel(self.class_model) # populate perm list self.perms_model = PermListModel(self, self.policy) self.perms.setModel(self.perms_model) # populate bool list self.bool_model = SEToolsListModel(self) self.bool_model.item_list = sorted(self.policy.bools()) self.bool_criteria.setModel(self.bool_model) # set up results self.table_results_model = TERuleTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.terulequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.set_source_regex(self.source_regex.isChecked()) self.set_target_regex(self.target_regex.isChecked()) self.set_default_regex(self.default_regex.isChecked()) self.toggle_xperm_criteria() self.criteria_frame.setHidden(not self.criteria_expander.isChecked()) self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.buttonBox.clicked.connect(self.run) self.allowxperm.toggled.connect(self.toggle_xperm_criteria) self.auditallowxperm.toggled.connect(self.toggle_xperm_criteria) self.neverallowxperm.toggled.connect(self.toggle_xperm_criteria) self.dontauditxperm.toggled.connect(self.toggle_xperm_criteria) self.clear_ruletypes.clicked.connect(self.clear_all_ruletypes) self.all_ruletypes.clicked.connect(self.set_all_ruletypes) self.source.textEdited.connect(self.clear_source_error) self.source.editingFinished.connect(self.set_source) self.source_regex.toggled.connect(self.set_source_regex) self.target.textEdited.connect(self.clear_target_error) self.target.editingFinished.connect(self.set_target) self.target_regex.toggled.connect(self.set_target_regex) self.tclass.selectionModel().selectionChanged.connect(self.set_tclass) self.invert_class.clicked.connect(self.invert_tclass_selection) self.perms.selectionModel().selectionChanged.connect(self.set_perms) self.invert_perms.clicked.connect(self.invert_perms_selection) self.xperms.textEdited.connect(self.clear_xperm_error) self.xperms.editingFinished.connect(self.set_xperm) self.default_type.textEdited.connect(self.clear_default_error) self.default_type.editingFinished.connect(self.set_default_type) self.default_regex.toggled.connect(self.set_default_regex) self.bool_criteria.selectionModel().selectionChanged.connect(self.set_bools) # # Ruletype criteria # def _set_ruletypes(self, value): self.allow.setChecked(value) self.allowxperm.setChecked(value) self.auditallow.setChecked(value) self.auditallowxperm.setChecked(value) self.neverallow.setChecked(value) self.neverallowxperm.setChecked(value) self.dontaudit.setChecked(value) self.dontauditxperm.setChecked(value) self.type_transition.setChecked(value) self.type_member.setChecked(value) self.type_change.setChecked(value) def set_all_ruletypes(self): self._set_ruletypes(True) def clear_all_ruletypes(self): self._set_ruletypes(False) # # Source criteria # def clear_source_error(self): self.clear_criteria_error(self.source, "Match the source type/attribute of the rule.") def set_source(self): try: self.query.source = self.source.text() except Exception as ex: self.log.error("Source type/attribute error: {0}".format(ex)) self.set_criteria_error(self.source, ex) def set_source_regex(self, state): self.log.debug("Setting source_regex {0}".format(state)) self.query.source_regex = state self.clear_source_error() self.set_source() # # Target criteria # def clear_target_error(self): self.clear_criteria_error(self.target, "Match the target type/attribute of the rule.") def set_target(self): try: self.query.target = self.target.text() except Exception as ex: self.log.error("Target type/attribute error: {0}".format(ex)) self.set_criteria_error(self.target, ex) def set_target_regex(self, state): self.log.debug("Setting target_regex {0}".format(state)) self.query.target_regex = state self.clear_target_error() self.set_target() # # Class criteria # def set_tclass(self): selected_classes = [] for index in self.tclass.selectionModel().selectedIndexes(): selected_classes.append(self.class_model.data(index, Qt.UserRole)) self.query.tclass = selected_classes self.perms_model.set_classes(selected_classes) def invert_tclass_selection(self): invert_list_selection(self.tclass.selectionModel()) # # Permissions criteria # def set_perms(self): selected_perms = [] for index in self.perms.selectionModel().selectedIndexes(): selected_perms.append(self.perms_model.data(index, Qt.UserRole)) self.query.perms = selected_perms def invert_perms_selection(self): invert_list_selection(self.perms.selectionModel()) # # Extended permission criteria # def toggle_xperm_criteria(self): mode = any((self.allowxperm.isChecked(), self.auditallowxperm.isChecked(), self.neverallowxperm.isChecked(), self.dontauditxperm.isChecked())) self.xperms.setEnabled(mode) self.xperms_equal.setEnabled(mode) def clear_xperm_error(self): self.clear_criteria_error(self.xperms, "Match the extended permissions of the rule. " "Comma-separated permissions or ranges of permissions.") def set_xperm(self): try: text = self.xperms.text() if text: self.query.xperms = xperm_str_to_tuple_ranges(text) else: self.query.xperms = None except Exception as ex: self.log.error("Extended permissions error: {0}".format(ex)) self.set_criteria_error(self.xperms, ex) # # Default criteria # def clear_default_error(self): self.clear_criteria_error(self.default_type, "Match the default type the rule.") def set_default_type(self): self.query.default_regex = self.default_regex.isChecked() try: self.query.default = self.default_type.text() except Exception as ex: self.log.error("Default type error: {0}".format(ex)) self.set_criteria_error(self.default_type, ex) def set_default_regex(self, state): self.log.debug("Setting default_regex {0}".format(state)) self.query.default_regex = state self.clear_default_error() self.set_default_type() # # Boolean criteria # def set_bools(self): selected_bools = [] for index in self.bool_criteria.selectionModel().selectedIndexes(): selected_bools.append(self.bool_model.data(index, Qt.UserRole)) self.query.boolean = selected_bools # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "allow", "allowxperm", "auditallow", "auditallowxperm", "neverallow", "neverallowxperm", "dontaudit", "dontauditxperm", "type_transition", "type_change", "type_member", "source_indirect", "source_regex", "target_indirect", "target_regex", "perms_subset", "xperms_equal", "default_regex", "bools_equal"]) save_lineedits(self, settings, ["source", "target", "xperms", "default_type"]) save_listviews(self, settings, ["tclass", "perms", "bool_criteria"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["allow", "allowxperm", "auditallow", "auditallowxperm", "neverallow", "neverallowxperm", "dontaudit", "dontauditxperm", "type_transition", "type_change", "type_member", "criteria_expander", "notes_expander", "source_indirect", "source_regex", "target_indirect", "target_regex", "perms_subset", "xperms_equal", "default_regex", "bools_equal"]) load_lineedits(self, settings, ["source", "target", "xperms", "default_type"]) load_listviews(self, settings, ["tclass", "perms", "bool_criteria"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. rule_types = [] max_results = 0 if self.allow.isChecked(): rule_types.append("allow") max_results += self.policy.allow_count if self.allowxperm.isChecked(): rule_types.append("allowxperm") max_results += self.policy.allowxperm_count if self.auditallow.isChecked(): rule_types.append("auditallow") max_results += self.policy.auditallow_count if self.auditallowxperm.isChecked(): rule_types.append("auditallowxperm") max_results += self.policy.auditallowxperm_count if self.neverallow.isChecked(): rule_types.append("neverallow") max_results += self.policy.neverallow_count if self.neverallowxperm.isChecked(): rule_types.append("neverallowxperm") max_results += self.policy.neverallowxperm_count if self.dontaudit.isChecked(): rule_types.append("dontaudit") max_results += self.policy.dontaudit_count if self.dontauditxperm.isChecked(): rule_types.append("dontauditxperm") max_results += self.policy.dontauditxperm_count if self.type_transition.isChecked(): rule_types.append("type_transition") max_results += self.policy.type_transition_count if self.type_member.isChecked(): rule_types.append("type_member") max_results += self.policy.type_member_count if self.type_change.isChecked(): rule_types.append("type_change") max_results += self.policy.type_change_count self.query.ruletype = rule_types self.query.source_indirect = self.source_indirect.isChecked() self.query.target_indirect = self.target_indirect.isChecked() self.query.perms_subset = self.perms_subset.isChecked() self.query.boolean_equal = self.bools_equal.isChecked() # if query is broad, show warning. if not any((self.query.source, self.query.target, self.query.tclass, self.query.perms, self.query.xperms, self.query.default, self.query.boolean)) \ and max_results > 1000: reply = QMessageBox.question( self, "Continue?", "This is a broad query, estimated to return {0} results. Continue?". format(max_results), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.No: return # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} type enforcement rule(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the permissions column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(4) > 400: header.resizeSection(4, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/terulequery.ui000066400000000000000000001051741402045477700213060ustar00rootroot00000000000000 TERuleQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 6 6 6 6 3 0 0 0 80 Optionally enter notes here about the query. Enter notes here. 0 2 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true 0 1 Show or hide the notes field (no data is lost) Notes Show or hide the search criteria (no settings are lost) Criteria true Qt::Horizontal 40 20 0 0 Show: 0 0 16777215 20 12 75 true Type Enforcement Rule Query 0 1 16777215 16777215 QFrame::StyledPanel QFrame::Raised 6 6 6 6 3 16777215 100 Target Type/Attribute 6 6 6 6 3 0 0 150 0 250 16777215 Use regular expressions to match the target type/attribute. Regex If the rule target is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Qt::Horizontal 113 20 0 0 16777215 150 Rule Type 6 6 6 6 3 Select All Auditallow Dontaudit Qt::Horizontal 40 20 Allow true Neverallow Clear false Neverallowxperms Allowxperms true Auditallowxperms Type_transition Type_change Type_member Dontauditxperms Default Type 6 6 6 6 3 0 0 150 0 250 16777215 Qt::Horizontal 40 20 Use regular expressions to match the default type. Regex 16777215 100 Source Type/Attribute 6 6 6 6 3 Qt::Horizontal 40 20 0 0 150 0 250 16777215 Use regular expressions to match the source type/attribute. Regex If the rule source is an attribute, indirect will match the criteria against the contents of the attribute, rather than the attribute itself. Indirect true Object Class 6 6 6 6 3 Qt::Horizontal 40 20 Clear Invert Qt::Vertical 20 40 0 0 250 16777215 Match the object class of the rule. QAbstractItemView::ExtendedSelection Booleans in Conditional Expression 6 6 6 6 3 0 0 250 16777215 Booleans used in the rule's conditional expression. QAbstractItemView::ExtendedSelection Qt::Horizontal 40 20 Clear A matching rule will use a set of Booleans in its conditional expression equal to the selected Booleans. Equal Qt::Vertical 20 40 QDialogButtonBox::Apply Permission Set 6 6 6 6 3 A matching rule will have an extended permission set equal to the listed extended permissions. Equal Invert Clear Qt::Horizontal 40 20 A matching rule will have all of the selected permissions. Match All Qt::Vertical 20 40 0 0 250 16777215 The list of permissions common to selected object classes. QAbstractItemView::ExtendedSelection Enter extended permissions here. ruletype_criteria source_criteria target_criteria class_criteria perms_criteria default_criteria booleans_criteria buttonBox SEToolsTableView QTableView
setoolsgui/tableview.h
criteria_expander notes_expander allow neverallow auditallow dontaudit clear_ruletypes all_ruletypes source source_indirect source_regex target target_indirect target_regex tclass clear_class invert_class perms clear_perms invert_perms perms_subset default_type default_regex bool_criteria clear_bools bools_equal results_frame table_results raw_results notes clear_bools clicked() bool_criteria clearSelection() 576 430 454 447 clear_class clicked() tclass clearSelection() 299 312 147 330 clear_perms clicked() perms clearSelection() 565 312 448 330 criteria_expander toggled(bool) criteria_frame setVisible(bool) 629 16 379 239 notes_expander toggled(bool) notes setVisible(bool) 735 16 386 776
setools-4.4.0/setoolsgui/apol/typeattrquery.py000066400000000000000000000204661402045477700216750ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TypeAttributeQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..typeattrmodel import TypeAttributeTableModel, typeattr_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TypeAttributeQueryTab(AnalysisTab): """TypeAttribute browser and query tab.""" section = AnalysisSection.Components tab_title = "Type Attributes" mlsonly = False def __init__(self, parent, policy, perm_map): super(TypeAttributeQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TypeAttributeQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.typeattrquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/typeattrquery.ui") # populate attr list self.attr_model = SEToolsListModel(self) self.attr_model.item_list = sorted(r for r in self.policy.typeattributes()) self.attrs.setModel(self.attr_model) # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # set up results self.table_results_model = TypeAttributeTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.typeattrquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.attrs.doubleClicked.connect(self.get_detail) self.attrs.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.types.selectionModel().selectionChanged.connect(self.set_types) self.invert_types.clicked.connect(self.invert_type_selection) self.buttonBox.clicked.connect(self.run) # # Attribute browser # def get_detail(self): # .ui is set for single item selection. index = self.attrs.selectedIndexes()[0] item = self.attr_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) typeattr_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the attribute name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Type attribute name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Type criteria # def set_types(self): selected_types = [] for index in self.types.selectionModel().selectedIndexes(): selected_types.append(self.type_model.data(index, Qt.UserRole)) self.query.types = selected_types def invert_type_selection(self): invert_list_selection(self.types.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["types"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "types_any", "types_equal"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["types"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.types_equal = self.types_equal.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} attribute(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the types column width is too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/typeattrquery.ui000066400000000000000000000423241402045477700216570ustar00rootroot00000000000000 TypeAttributeQueryTab_ui 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Type Attributes 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Attribute Browser 0 0 16777215 16777215 Search Criteria Types 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching attribute will have a role set equal to the selected types. Equal A matching attribute will have any of the selected types. Any true 0 0 250 16777215 Match the type set of the attribute. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Attribute Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the attribute's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander attrs name name_regex types types_any types_equal clear_types invert_types results_frame table_results raw_results notes clear_types clicked() types clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/typequery.py000066400000000000000000000206631402045477700210010ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import TypeQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..typemodel import TypeTableModel, type_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class TypeQueryTab(AnalysisTab): """Type browser and query tab.""" section = AnalysisSection.Components tab_title = "Types" mlsonly = False def __init__(self, parent, policy, perm_map): super(TypeQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = TypeQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.typequery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/typequery.ui") # populate type list self.type_model = SEToolsListModel(self) self.type_model.item_list = sorted(self.policy.types()) self.types.setModel(self.type_model) # populate attribute list self.attr_model = SEToolsListModel(self) self.attr_model.item_list = sorted(self.policy.typeattributes()) self.attrs.setModel(self.attr_model) # set up results self.table_results_model = TypeTableModel(self) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.typequery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.types.doubleClicked.connect(self.get_detail) self.types.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.attrs.selectionModel().selectionChanged.connect(self.set_attrs) self.invert_attrs.clicked.connect(self.invert_attr_selection) self.buttonBox.clicked.connect(self.run) # # Type browser # def get_detail(self): # .ui is set for single item selection. index = self.types.selectedIndexes()[0] item = self.type_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) type_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the type name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("Type name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Attribute criteria # def set_attrs(self): selected_attrs = [] for index in self.attrs.selectionModel().selectedIndexes(): selected_attrs.append(self.attr_model.data(index, Qt.UserRole)) self.query.attrs = selected_attrs def invert_attr_selection(self): invert_list_selection(self.attrs.selectionModel()) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "attrs_any", "attrs_equal", "permissive"]) save_lineedits(self, settings, ["name"]) save_listviews(self, settings, ["attrs"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "attrs_any", "attrs_equal", "permissive"]) load_lineedits(self, settings, ["name"]) load_listviews(self, settings, ["attrs"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.name_regex = self.name_regex.isChecked() self.query.attrs_equal = self.attrs_equal.isChecked() self.query.permissive = self.permissive.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} type(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() # If the attrs or alias column widths are too long, pull back # to a reasonable size header = self.table_results.horizontalHeader() if header.sectionSize(1) > 400: header.resizeSection(1, 400) if header.sectionSize(2) > 400: header.resizeSection(2, 400) if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/typequery.ui000066400000000000000000000441361402045477700207670ustar00rootroot00000000000000 UserQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true Types 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal Type Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Permissive A matching type will be permissive. Permisive Attributes 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching type will have an attribute set equal to the selected attributes. Equal A matching type will have any of the selected attributes. Any true 0 0 250 16777215 Match the attribute set of the type. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 Type Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the type's name. Regex QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander types name name_regex permissive attrs attrs_any attrs_equal clear_attrs invert_attrs results_frame table_results raw_results notes clear_attrs clicked() attrs clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/userquery.py000066400000000000000000000254131402045477700207740ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from PyQt5.QtCore import Qt, QSortFilterProxyModel, QStringListModel, QThread from PyQt5.QtGui import QPalette, QTextCursor from PyQt5.QtWidgets import QCompleter, QHeaderView, QMessageBox, QProgressDialog from setools import UserQuery from ..logtosignal import LogHandlerToSignal from ..models import SEToolsListModel, invert_list_selection from ..usermodel import UserTableModel, user_detail from .analysistab import AnalysisSection, AnalysisTab from .exception import TabFieldError from .queryupdater import QueryResultsUpdater from .workspace import load_checkboxes, load_lineedits, load_listviews, load_textedits, \ save_checkboxes, save_lineedits, save_listviews, save_textedits class UserQueryTab(AnalysisTab): """User browser and query tab.""" section = AnalysisSection.Components tab_title = "Users" mlsonly = False def __init__(self, parent, policy, perm_map): super(UserQueryTab, self).__init__(parent) self.log = logging.getLogger(__name__) self.policy = policy self.query = UserQuery(policy) self.setupUi() def __del__(self): with suppress(RuntimeError): self.thread.quit() self.thread.wait(5000) logging.getLogger("setools.userquery").removeHandler(self.handler) def setupUi(self): self.load_ui("apol/userquery.ui") # populate user list self.user_model = SEToolsListModel(self) self.user_model.item_list = sorted(self.policy.users()) self.users.setModel(self.user_model) # populate role list self.role_model = SEToolsListModel(self) self.role_model.item_list = sorted(r for r in self.policy.roles() if r != "object_r") self.roles.setModel(self.role_model) # set up results self.table_results_model = UserTableModel(self, self.policy.mls) self.sort_proxy = QSortFilterProxyModel(self) self.sort_proxy.setSourceModel(self.table_results_model) self.table_results.setModel(self.sort_proxy) self.table_results.sortByColumn(0, Qt.AscendingOrder) # setup indications of errors on level/range self.errors = set() self.orig_palette = self.name.palette() self.error_palette = self.name.palette() self.error_palette.setColor(QPalette.Base, Qt.red) self.clear_name_error() if self.policy.mls: self.clear_level_error() self.clear_range_error() else: # disable level and range criteria self.level_criteria.setEnabled(False) self.level_criteria.setToolTip("MLS is disabled in this policy.") self.level.setToolTip("MLS is disabled in this policy.") self.level_exact.setToolTip("MLS is disabled in this policy.") self.level_dom.setToolTip("MLS is disabled in this policy.") self.level_domby.setToolTip("MLS is disabled in this policy.") self.range_criteria.setEnabled(False) self.range_criteria.setToolTip("MLS is disabled in this policy.") self.range_.setToolTip("MLS is disabled in this policy.") self.range_exact.setToolTip("MLS is disabled in this policy.") self.range_overlap.setToolTip("MLS is disabled in this policy.") self.range_subset.setToolTip("MLS is disabled in this policy.") self.range_superset.setToolTip("MLS is disabled in this policy.") # set up processing thread self.thread = QThread() self.worker = QueryResultsUpdater(self.query, self.table_results_model) self.worker.moveToThread(self.thread) self.worker.raw_line.connect(self.raw_results.appendPlainText) self.worker.finished.connect(self.update_complete) self.worker.finished.connect(self.thread.quit) self.thread.started.connect(self.worker.update) # create a "busy, please wait" dialog self.busy = QProgressDialog(self) self.busy.setModal(True) self.busy.setRange(0, 0) self.busy.setMinimumDuration(0) self.busy.canceled.connect(self.thread.requestInterruption) self.busy.reset() # update busy dialog from query INFO logs self.handler = LogHandlerToSignal() self.handler.message.connect(self.busy.setLabelText) logging.getLogger("setools.userquery").addHandler(self.handler) # Ensure settings are consistent with the initial .ui state self.notes.setHidden(not self.notes_expander.isChecked()) # connect signals self.users.doubleClicked.connect(self.get_detail) self.users.get_detail.triggered.connect(self.get_detail) self.name.textEdited.connect(self.clear_name_error) self.name.editingFinished.connect(self.set_name) self.name_regex.toggled.connect(self.set_name_regex) self.roles.selectionModel().selectionChanged.connect(self.set_roles) self.invert_roles.clicked.connect(self.invert_role_selection) self.level.textEdited.connect(self.clear_level_error) self.level.editingFinished.connect(self.set_level) self.range_.textEdited.connect(self.clear_range_error) self.range_.editingFinished.connect(self.set_range) self.buttonBox.clicked.connect(self.run) # # User browser # def get_detail(self): # .ui is set for single item selection. index = self.users.selectedIndexes()[0] item = self.user_model.data(index, Qt.UserRole) self.log.debug("Generating detail window for {0}".format(item)) user_detail(self, item) # # Name criteria # def clear_name_error(self): self.clear_criteria_error(self.name, "Match the user name.") def set_name(self): try: self.query.name = self.name.text() except Exception as ex: self.log.error("User name error: {0}".format(ex)) self.set_criteria_error(self.name, ex) def set_name_regex(self, state): self.log.debug("Setting name_regex {0}".format(state)) self.query.name_regex = state self.clear_name_error() self.set_name() # # Role criteria # def set_roles(self): selected_roles = [] for index in self.roles.selectionModel().selectedIndexes(): selected_roles.append(self.role_model.data(index, Qt.UserRole)) self.query.roles = selected_roles def invert_role_selection(self): invert_list_selection(self.roles.selectionModel()) # # Default level criteria # def clear_level_error(self): self.clear_criteria_error(self.level, "Match the default level of the user.") def set_level(self): try: self.query.level = self.level.text() except Exception as ex: self.log.info("Level criterion error: " + str(ex)) self.set_criteria_error(self.level, ex) # # Range criteria # def clear_range_error(self): self.clear_criteria_error(self.range_, "Match the default range of the user.") def set_range(self): try: self.query.range_ = self.range_.text() except Exception as ex: self.log.info("Range criterion error: " + str(ex)) self.set_criteria_error(self.range_, ex) # # Save/Load tab # def save(self): """Return a dictionary of settings.""" if self.errors: raise TabFieldError("Field(s) are in error: {0}". format(" ".join(o.objectName() for o in self.errors))) settings = {} save_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "roles_any", "roles_equal", "level_exact", "level_dom", "level_domby", "range_exact", "range_overlap", "range_subset", "range_superset"]) save_lineedits(self, settings, ["name", "level", "range_"]) save_listviews(self, settings, ["roles"]) save_textedits(self, settings, ["notes"]) return settings def load(self, settings): load_checkboxes(self, settings, ["criteria_expander", "notes_expander", "name_regex", "roles_any", "roles_equal", "level_exact", "level_dom", "level_domby", "range_exact", "range_overlap", "range_subset", "range_superset"]) load_lineedits(self, settings, ["name", "level", "range_"]) load_listviews(self, settings, ["roles"]) load_textedits(self, settings, ["notes"]) # # Results runner # def run(self, button): # right now there is only one button. self.query.roles_equal = self.roles_equal.isChecked() self.query.level_dom = self.level_dom.isChecked() self.query.level_domby = self.level_domby.isChecked() self.query.range_overlap = self.range_overlap.isChecked() self.query.range_subset = self.range_subset.isChecked() self.query.range_superset = self.range_superset.isChecked() # start processing self.busy.setLabelText("Processing query...") self.busy.show() self.raw_results.clear() self.thread.start() def update_complete(self, count): self.log.info("{0} user(s) found.".format(count)) # update sizes/location of result displays if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's columns; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeColumnsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Resizing the result table's rows; GUI may be unresponsive") self.busy.repaint() self.table_results.resizeRowsToContents() if not self.busy.wasCanceled(): self.busy.setLabelText("Moving the raw result to top; GUI may be unresponsive") self.busy.repaint() self.raw_results.moveCursor(QTextCursor.Start) self.busy.reset() setools-4.4.0/setoolsgui/apol/userquery.ui000066400000000000000000000612621402045477700207630ustar00rootroot00000000000000 UserQueryTab 0 0 774 846 QAbstractScrollArea::AdjustToContents true 0 0 772 844 0 0 0 0 16777215 20 11 75 true SELinux Users 0 80 Optionally enter notes here about the query. Enter notes here. Qt::Horizontal 440 20 Show: Show or hide the search criteria (no settings are lost) Criteria true Show or hide the notes field (no data is lost) Notes 0 1 Qt::Horizontal User Browser 0 0 16777215 16777215 Search Criteria 16777215 120 Default MLS Level 6 6 6 6 3 0 0 150 20 250 16777215 The level criterion will match if it is equal to the user's default level. Equal true The level criterion will match if it dominates the user's default level. Dominate The level criterion will match if it is dominated by the user's default level. Dominated Roles 6 6 6 6 3 Clear Qt::Horizontal 40 20 Invert A matching user will have a role set equal to the selected roles. Equal A matching user will have any of the selected roles. Any true 0 0 250 16777215 Match the role set of the user. QAbstractItemView::ExtendedSelection Qt::Vertical 20 40 16777215 120 User Name 6 6 6 6 3 0 0 150 20 250 16777215 Use regular expressions to match the user's name. Regex 16777215 16777215 MLS Range 6 6 6 6 3 0 0 150 20 250 16777215 The range criterion will match if it is equal to the user's range. Equal true The range criterion will match if it is a subset of the user's range. Subset The range criterion will match if it overlaps the user's range. Overlap The range criterion will match if it is a superset of the user's range. Superset Qt::Vertical 20 40 QDialogButtonBox::Apply 0 1 0 0 0 Results 6 6 6 6 0 0 QAbstractScrollArea::AdjustIgnored true true 0 0 Raw Results 6 6 6 6 0 0 0 0 Monospace QPlainTextEdit::NoWrap true splitter notes label label_2 horizontalSpacer criteria_expander notes_expander SEToolsTableView QTableView
setoolsgui/tableview.h
GetDetailsListView QListView
setoolsgui/getdetailslist.h
criteria_expander notes_expander users name name_regex roles roles_any roles_equal clear_roles invert_roles level level_exact level_dom level_domby range_ range_exact range_overlap range_subset range_superset results_frame table_results raw_results notes clear_roles clicked() roles clearSelection() 429 99 319 184 notes_expander toggled(bool) notes setVisible(bool) 732 20 386 754 criteria_expander toggled(bool) criteria_frame setVisible(bool) 583 20 496 226
setools-4.4.0/setoolsgui/apol/workspace.py000066400000000000000000000175711402045477700207340ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import re import logging import setools from PyQt5.QtCore import Qt, QItemSelectionModel def save_checkboxes(tab, settings, checkboxes): """ Save settings from the checkable buttons (e.g. QCheckbox) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. checkboxes A list of attribute names (str) of buttons in the tab. """ for entry in checkboxes: checkbox = getattr(tab, entry) settings[entry] = checkbox.isChecked() def load_checkboxes(tab, settings, checkboxes): """ Load settings into the checkable buttons (e.g. QCheckbox) in the tab. Parameters: tab The tab object. settings The dictionary of settings. checkboxes A list of attribute names (str) of buttons in the tab. """ log = logging.getLogger(__name__) # next set options for entry in checkboxes: checkbox = getattr(tab, entry) try: checkbox.setChecked(bool(settings[entry])) except KeyError: log.warning("{0} option missing from settings file.".format(entry)) def save_lineedits(tab, settings, lines): """ Save settings into the QLineEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. lines A list of attribute names (str) of QLineEdits in the tab. """ # set line edits for entry in lines: lineedit = getattr(tab, entry) settings[entry] = lineedit.text() def load_lineedits(tab, settings, lines): """ Load settings into the QLineEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. lines A list of attribute names (str) of QLineEdits in the tab. """ log = logging.getLogger(__name__) # set line edits for entry in lines: lineedit = getattr(tab, entry) try: lineedit.setText(str(settings[entry])) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) def save_textedits(tab, settings, edits): """ Save settings into the QTextEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. edits A list of attribute names (str) of QTextEdits in the tab. """ # set line edits for entry in edits: textedit = getattr(tab, entry) settings[entry] = textedit.toPlainText() def load_textedits(tab, settings, edits): """ Load settings into the QTextEdit(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. edits A list of attribute names (str) of QTextEdits in the tab. """ log = logging.getLogger(__name__) # set line edits for entry in edits: textedit = getattr(tab, entry) try: textedit.setPlainText(str(settings[entry])) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) def save_listviews(tab, settings, listviews): """ Save settings from the QListView selection(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. listviews A list of attribute names (str) of QListViews in the tab. """ for entry in listviews: listview = getattr(tab, entry) datamodel = listview.model() selections = [] for index in listview.selectedIndexes(): item = datamodel.data(index, Qt.DisplayRole) selections.append(item) settings[entry] = selections def load_listviews(tab, settings, listviews): """ Load settings into the QListView selection(s) in the tab. Parameters: tab The tab object. settings The dictionary of settings. listviews A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) # set list selections for entry in listviews: try: selections = list(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue except TypeError: msg = "Invalid list for {0} criteria: {1!r}".format(entry, settings[entry]) log.critical(msg) raise TypeError(msg) if not selections: continue listview = getattr(tab, entry) selectionmodel = listview.selectionModel() selectionmodel.clear() datamodel = listview.selectionModel().model() for row in range(datamodel.rowCount()): index = datamodel.createIndex(row, 0) item = datamodel.data(index, Qt.DisplayRole) if item in selections: selectionmodel.select(index, QItemSelectionModel.Select) def save_comboboxes(tab, settings, comboboxes): """ Save settings from the QComboBox selection in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. comboboxes A list of attribute names (str) of QListViews in the tab. """ for entry in comboboxes: combobox = getattr(tab, entry) settings[entry] = combobox.currentData(Qt.DisplayRole) def load_comboboxes(tab, settings, comboboxes): """ Load settings into the QComboBox selection in the tab. Parameters: tab The tab object. settings The dictionary of settings. comboboxes A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) for entry in comboboxes: try: selection = str(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue combobox = getattr(tab, entry) combobox.setCurrentText(selection) def save_spinboxes(tab, settings, spinboxes): """ Save settings from the QSpinBox value in the tab. Parameters: tab The tab object. settings The dictionary of settings. This will be mutated. spinboxes A list of attribute names (str) of QListViews in the tab. """ for entry in spinboxes: spinbox = getattr(tab, entry) settings[entry] = spinbox.value() def load_spinboxes(tab, settings, spinboxes): """ Load settings into the QSpinBox value in the tab. Parameters: tab The tab object. settings The dictionary of settings. spinboxes A list of attribute names (str) of QListViews in the tab. """ log = logging.getLogger(__name__) for entry in spinboxes: try: value = int(settings[entry]) except KeyError: log.warning("{0} criteria missing from settings file.".format(entry)) continue except (ValueError, TypeError) as ex: msg = "Invalid value for {0} criteria: {1!r}.".format(entry, settings[entry]) log.critical(msg) raise ex.__class__(msg) spinbox = getattr(tab, entry) spinbox.setValue(value) setools-4.4.0/setoolsgui/boolmodel.py000066400000000000000000000034711402045477700177510ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from .details import DetailsPopup from .models import SEToolsTableModel def boolean_detail(parent, boolean): """ Create a dialog box for Booleanean details. Parameters: parent The parent Qt Widget bool The boolean """ detail = DetailsPopup(parent, "Boolean detail: {0}".format(boolean)) detail.append_header("Default State: {0}".format(boolean.state)) detail.show() class BooleanTableModel(SEToolsTableModel): """Table-based model for booleans.""" headers = ["Name", "Default State"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() boolean = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return boolean.name elif col == 1: return str(boolean.state) elif role == Qt.UserRole: # get the whole rule for boolean boolean return boolean setools-4.4.0/setoolsgui/boundsmodel.py000066400000000000000000000026411402045477700203060ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class BoundsTableModel(SEToolsTableModel): """Table-based model for *bounds.""" headers = ["Rule Type", "Parent", "Child"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.ruletype.name elif col == 1: return item.parent.name elif col == 2: return item.child.name elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/commonmodel.py000066400000000000000000000036051402045477700203050ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.exception import NoCommon from .details import DetailsPopup from .models import SEToolsTableModel def common_detail(parent, common): """ Create a dialog box for common perm set details. Parameters: parent The parent Qt Widget class_ The type """ detail = DetailsPopup(parent, "Common detail: {0}".format(common)) detail.append_header("Permissions ({0}):".format(len(common.perms))) for p in sorted(common.perms): detail.append(" {0}".format(p)) detail.show() class CommonTableModel(SEToolsTableModel): """Table-based model for common permission sets.""" headers = ["Name", "Permissions"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: return ", ".join(sorted(item.perms)) elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/constraintmodel.py000066400000000000000000000032741402045477700212030ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.exception import ConstraintUseError from .models import SEToolsTableModel class ConstraintTableModel(SEToolsTableModel): """A table-based model for constraints.""" headers = ["Rule Type", "Class", "Permissions", "Expression"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.tclass.name elif col == 2: try: return ", ".join(sorted(rule.perms)) except ConstraintUseError: return None elif col == 3: return str(rule.expression) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/defaultmodel.py000066400000000000000000000031421402045477700204350ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from contextlib import suppress from PyQt5.QtCore import Qt from .models import SEToolsTableModel class DefaultTableModel(SEToolsTableModel): """Table-based model for default_*.""" headers = ["Rule Type", "Class", "Default", "Default Range"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.ruletype.name elif col == 1: return item.tclass.name elif col == 2: return item.default.name elif col == 3: with suppress(AttributeError): return item.default_range.name elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/detail_popup.ui000066400000000000000000000022101402045477700204350ustar00rootroot00000000000000 DetailsPopup 0 0 400 300 Dialog Qt::Horizontal QDialogButtonBox::Close buttonBox clicked(QAbstractButton*) DetailsPopup close() 248 254 157 274 setools-4.4.0/setoolsgui/details.py000066400000000000000000000036161402045477700174230ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from PyQt5.QtGui import QFont, QTextCursor from PyQt5.QtWidgets import QDialog from .widget import SEToolsWidget class DetailsPopup(SEToolsWidget, QDialog): """A generic non-modal popup with a text field to write detailed info.""" # TODO: make the font changes relative # instead of setting absolute values def __init__(self, parent, title=None): super(DetailsPopup, self).__init__(parent) self.log = logging.getLogger(__name__) self.setupUi(title) def setupUi(self, title): self.load_ui("detail_popup.ui") if title: self.title = title @property def title(self): self.windowTitle(self) @title.setter def title(self, text): self.setWindowTitle(text) def append(self, text): self.contents.setFontWeight(QFont.Normal) self.contents.setFontPointSize(9) self.contents.append(text) def append_header(self, text): self.contents.setFontWeight(QFont.Black) self.contents.setFontPointSize(11) self.contents.append(text) def show(self): self.contents.moveCursor(QTextCursor.Start) super(DetailsPopup, self).show() setools-4.4.0/setoolsgui/fsusemodel.py000066400000000000000000000026341402045477700201430ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class FSUseTableModel(SEToolsTableModel): """Table-based model for fs_use_*.""" headers = ["Ruletype", "FS Type", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.fs elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/genfsconmodel.py000066400000000000000000000034621402045477700206200ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import stat from PyQt5.QtCore import Qt from .models import SEToolsTableModel class GenfsconTableModel(SEToolsTableModel): """Table-based model for genfscons.""" headers = ["FS Type", "Path", "File Type", "Context"] _filetype_to_text = { 0: "Any", stat.S_IFBLK: "Block", stat.S_IFCHR: "Character", stat.S_IFDIR: "Directory", stat.S_IFIFO: "Pipe (FIFO)", stat.S_IFREG: "Regular File", stat.S_IFLNK: "Symbolic Link", stat.S_IFSOCK: "Socket"} def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.fs elif col == 1: return rule.path elif col == 2: return self._filetype_to_text[rule.filetype] elif col == 3: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/getdetailslist.py000066400000000000000000000023521402045477700210130ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtGui import QCursor from PyQt5.QtWidgets import QAction, QListView, QMenu class GetDetailsListView(QListView): """A QListView widget with more details context menu.""" def __init__(self, parent): super(GetDetailsListView, self).__init__(parent) # set up right-click context menu self.get_detail = QAction("More details...", self) self.menu = QMenu(self) self.menu.addAction(self.get_detail) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) setools-4.4.0/setoolsgui/ibendportconmodel.py000066400000000000000000000026601402045477700215030ustar00rootroot00000000000000# Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class IbendportconTableModel(SEToolsTableModel): """Table-based model for ibendportcons.""" headers = ["Device", "Endport", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.name elif col == 1: return str(rule.port) elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/ibpkeyconmodel.py000066400000000000000000000031721402045477700207770ustar00rootroot00000000000000# Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class IbpkeyconTableModel(SEToolsTableModel): """Table-based model for ibpkeycons.""" headers = ["Subnet Prefix", "Partition Keys", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(rule.subnet_prefix) elif col == 1: low, high = rule.pkeys if low == high: return "{0:#x}".format(low) else: return "{0:#x}-{1:#x}".format(low, high) elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/initsidmodel.py000066400000000000000000000025121402045477700204540ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class InitialSIDTableModel(SEToolsTableModel): """Table-based model for initial SIDs.""" headers = ["SID", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.name elif col == 1: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/listview.py000066400000000000000000000043411402045477700176400ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from collections import defaultdict from PyQt5.QtCore import Qt, QItemSelectionModel from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QAbstractItemView, QListView class SEToolsListView(QListView): """QListView class extended for SETools use.""" def __init__(self, parent): super(SEToolsListView, self).__init__(parent) self.log = logging.getLogger(__name__) def invert(self): """Invert the selection.""" if self.selectionMode() != QAbstractItemView.ExtendedSelection and \ self.selectionMode() != QAbstractItemView.MultiSelection: self.log.debug("Attempted to invert list {0} which doesn't have multiselect.". format(self.objectName())) return selection_model = self.selectionModel() model = self.model() for row in range(model.rowCount()): index = model.createIndex(row, 0) selection_model.select(index, QItemSelectionModel.Toggle) def selection(self, qt_role=Qt.UserRole): """ Generator which returns the selection. Parameter: qt_role The Qt model role. Default is Qt.UserRole. Yield: tuple(row, data) row The row number of the selection. data The data for the row, for the specified Qt role. """ model = self.model() for index in self.selectionModel().selectedIndexes(): yield index.row(), model.data(index, qt_role) setools-4.4.0/setoolsgui/logtosignal.py000066400000000000000000000026351402045477700203200ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from logging import Formatter, Handler, INFO from PyQt5.QtCore import pyqtSignal, QObject class LogHandlerToSignal(Handler, QObject): """ A Python logging Handler that sends log messages over Qt signals. By default the handler level is set to logging.INFO and only the message is signalled. Qt signals: message (str) A message from the Python logging system. """ message = pyqtSignal(str) def __init__(self): Handler.__init__(self) QObject.__init__(self) self.setLevel(INFO) self.setFormatter(Formatter('%(message)s')) def emit(self, record): msg = self.format(record) if msg: self.message.emit(msg) setools-4.4.0/setoolsgui/mlsmodel.py000066400000000000000000000045161402045477700176120ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from .details import DetailsPopup from .models import SEToolsTableModel def _mls_detail(parent, obj, objtype): """ Create a dialog box for category or sensitivity details. Parameters: parent The parent Qt Widget type_ The type """ detail = DetailsPopup(parent, "{0} detail: {1}".format(objtype, obj)) aliases = sorted(obj.aliases()) detail.append_header("Aliases ({0}):".format(len(aliases))) for a in aliases: detail.append(" {0}".format(a)) detail.show() def category_detail(parent, obj): """ Create a dialog box for category details. Parameters: parent The parent Qt Widget type_ The type """ _mls_detail(parent, obj, "Category") def sensitivity_detail(parent, obj): """ Create a dialog box for sensitivity details. Parameters: parent The parent Qt Widget type_ The type """ _mls_detail(parent, obj, "Sensitivity") class MLSComponentTableModel(SEToolsTableModel): """Table-based model for sensitivities and categories.""" headers = ["Name", "Aliases"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: return ", ".join(sorted(a for a in item.aliases())) elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/mlsrulemodel.py000066400000000000000000000031401402045477700204720ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class MLSRuleTableModel(SEToolsTableModel): """A table-based model for MLS rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Default Range"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.source.name elif col == 2: return rule.target.name elif col == 3: return rule.tclass.name elif col == 4: return str(rule.default) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/models.py000066400000000000000000000112551402045477700172570ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import logging from contextlib import suppress from typing import List from PyQt5.QtCore import QAbstractListModel, QItemSelectionModel, QAbstractTableModel, \ QModelIndex, QStringListModel, Qt from setools.exception import NoCommon def invert_list_selection(selection_model): """Invert the selection of a list-based model.""" model = selection_model.model() rowcount = model.rowCount() for row in range(rowcount): index = model.createIndex(row, 0) selection_model.select(index, QItemSelectionModel.Toggle) class SEToolsListModel(QAbstractListModel): """ The purpose of this model is to have the objects return their string representations for Qt.DisplayRole and return the object for Qt.UserRole. Some Python list-like functions are provided for altering the model: append and remove """ def __init__(self, parent): super(SEToolsListModel, self).__init__(parent) self.log = logging.getLogger(__name__) self._item_list = None @property def item_list(self): return self._item_list @item_list.setter def item_list(self, item_list): self.beginResetModel() self._item_list = item_list self.endResetModel() def rowCount(self, parent=QModelIndex()): if self.item_list: return len(self.item_list) else: return 0 def columnCount(self, parent=QModelIndex()): return 1 def append(self, item): """Append the item to the list.""" index = self.rowCount() self.beginInsertRows(QModelIndex(), index, index) self.item_list.append(item) self.endInsertRows() def remove(self, item): """Remove the first instance of the specified item from the list.""" try: row = self.item_list.index(item) except ValueError: self.log.debug("Attempted to remove item {0!r} but it is not in the list".format(item)) else: self.beginRemoveRows(QModelIndex(), row, row) del self.item_list[row] self.endRemoveRows() def data(self, index, role): if self.item_list and index.isValid(): row = index.row() item = self.item_list[row] if role == Qt.DisplayRole: return str(item) elif role == Qt.UserRole: return item class PermListModel(SEToolsListModel): """ A model that will return the intersection of permissions for the selected classes. If no classes are set, all permissions in the policy will be returned. """ def __init__(self, parent, policy): super(PermListModel, self).__init__(parent) self.policy = policy self.set_classes() def set_classes(self, classes=[]): permlist = set() # start will all permissions. for cls in self.policy.classes(): permlist.update(cls.perms) with suppress(NoCommon): permlist.update(cls.common.perms) # create intersection for cls in classes: cls_perms = set(cls.perms) with suppress(NoCommon): cls_perms.update(cls.common.perms) permlist.intersection_update(cls_perms) self.item_list = sorted(permlist) class SEToolsTableModel(QAbstractTableModel): """Base class for SETools table models.""" headers: List[str] = [] def __init__(self, parent): super(SEToolsTableModel, self).__init__(parent) self.resultlist = [] def headerData(self, section, orientation, role): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.headers[section] def rowCount(self, parent=QModelIndex()): if self.resultlist: return len(self.resultlist) else: return 0 def columnCount(self, parent=QModelIndex()): return len(self.headers) def data(self, index, role): raise NotImplementedError setools-4.4.0/setoolsgui/netifconmodel.py000066400000000000000000000026551402045477700206260ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class NetifconTableModel(SEToolsTableModel): """Table-based model for netifcons.""" headers = ["Device", "Device Context", "Packet Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.netif elif col == 1: return str(rule.context) elif col == 2: return str(rule.packet) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/nodeconmodel.py000066400000000000000000000025341402045477700204420ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class NodeconTableModel(SEToolsTableModel): """Table-based model for nodecons.""" headers = ["Network", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return str(rule.network.with_netmask) elif col == 1: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/objclassmodel.py000066400000000000000000000046541402045477700206220ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from itertools import chain from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.exception import NoCommon from .details import DetailsPopup from .models import SEToolsTableModel def class_detail(parent, class_): """ Create a dialog box for object class details. Parameters: parent The parent Qt Widget class_ The type """ detail = DetailsPopup(parent, "Object class detail: {0}".format(class_)) try: common = class_.common except NoCommon: pass else: detail.append_header("Inherits: {0}\n".format(common)) detail.append_header("Inherited permissions ({0}):".format(len(common.perms))) for p in sorted(common.perms): detail.append(" {0}".format(p)) detail.append("\n") detail.append_header("Permissions ({0}):".format(len(class_.perms))) for p in sorted(class_.perms): detail.append(" {0}".format(p)) detail.show() class ObjClassTableModel(SEToolsTableModel): """Table-based model for object classes.""" headers = ["Name", "Permissions"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: try: com_perms = item.common.perms except NoCommon: com_perms = [] return ", ".join(sorted(chain(com_perms, item.perms))) elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/portconmodel.py000066400000000000000000000031171402045477700204770ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from .models import SEToolsTableModel class PortconTableModel(SEToolsTableModel): """Table-based model for portcons.""" headers = ["Port/Port Range", "Protocol", "Context"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: low, high = rule.ports if low == high: return str(low) else: return "{0}-{1}".format(low, high) elif col == 1: return rule.protocol.name elif col == 2: return str(rule.context) elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/rbacrulemodel.py000066400000000000000000000036651402045477700206220ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.exception import RuleUseError from .models import SEToolsTableModel class RBACRuleTableModel(SEToolsTableModel): """A table-based model for RBAC rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Default Role"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.source.name elif col == 2: return rule.target.name elif col == 3: try: return rule.tclass.name except RuleUseError: # role allow return None elif col == 4: # next most common: default try: return rule.default.name except RuleUseError: return None elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/rolemodel.py000066400000000000000000000040351402045477700177540ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def role_detail(parent, role): """ Create a dialog box for role details. Parameters: parent The parent Qt Widget role The role """ detail = DetailsPopup(parent, "Role detail: {0}".format(role)) types = sorted(role.types()) detail.append_header("Types ({0}): ".format(len(types))) for t in types: detail.append(" {0}".format(t)) detail.show() class RoleTableModel(SEToolsTableModel): """Table-based model for roles.""" headers = ["Name", "Types"] def data(self, index, role): # There are two roles here. # The parameter, role, is the Qt role # The below item is a role in the list. if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: return ", ".join(sorted(t.name for t in item.types())) elif role == Qt.UserRole: # get the whole object return item setools-4.4.0/setoolsgui/tableview.py000066400000000000000000000071061402045477700177560ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import csv from PyQt5.QtCore import Qt from PyQt5.QtGui import QKeySequence, QCursor from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMenu, QTableView class SEToolsTableView(QTableView): """QTableView class extended for SETools use.""" def __init__(self, parent): super(SEToolsTableView, self).__init__(parent) # set up right-click context menu self.save_csv_action = QAction("Save table to CSV...", self) self.menu = QMenu(self) self.menu.addAction(self.save_csv_action) # connect signals self.save_csv_action.triggered.connect(self.choose_csv_save_location) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) def event(self, e): if e == QKeySequence.Copy or e == QKeySequence.Cut: datamodel = self.model() selected_text = [] current_row = None current_col = None prev_row = None prev_col = None for index in sorted(self.selectionModel().selectedIndexes()): current_row = index.row() current_col = index.column() if prev_row is not None and current_row != prev_row: selected_text.append('\n') elif prev_col is not None and current_col != prev_col: selected_text.append('\t') selected_text.append(datamodel.data(index, Qt.DisplayRole)) prev_row = current_row prev_col = current_col QApplication.clipboard().setText("".join(selected_text)) return True else: return super(SEToolsTableView, self).event(e) def choose_csv_save_location(self): filename = QFileDialog.getSaveFileName(self, "Save to CSV", "table.csv", "Comma Separated Values Spreadsheet (*.csv);;" "All Files (*)")[0] if filename: self.save_csv(filename) def save_csv(self, filename): """Save the current table data to the specified CSV file.""" datamodel = self.model() row_count = datamodel.rowCount() col_count = datamodel.columnCount() with open(filename, 'w') as fd: writer = csv.writer(fd, quoting=csv.QUOTE_MINIMAL) # write headers csv_row = [] for col in range(col_count): csv_row.append(datamodel.headerData(col, Qt.Horizontal, Qt.DisplayRole)) writer.writerow(csv_row) # write data for row in range(row_count): csv_row = [] for col in range(col_count): index = datamodel.index(row, col) csv_row.append(datamodel.data(index, Qt.DisplayRole)) writer.writerow(csv_row) setools-4.4.0/setoolsgui/terulemodel.py000066400000000000000000000046111402045477700203130ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from setools.exception import RuleNotConditional, RuleUseError from .models import SEToolsTableModel class TERuleTableModel(SEToolsTableModel): """A table-based model for TE rules.""" headers = ["Rule Type", "Source", "Target", "Object Class", "Permissions/Default Type", "Conditional Expression", "Conditional Block"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() rule = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return rule.ruletype.name elif col == 1: return rule.source.name elif col == 2: return rule.target.name elif col == 3: return rule.tclass.name elif col == 4: try: if rule.extended: return "{0.xperm_type}: {0.perms:,}".format(rule) else: return ", ".join(sorted(rule.perms)) except RuleUseError: return rule.default.name elif col == 5: try: return str(rule.conditional) except RuleNotConditional: return None elif col == 6: try: return str(rule.conditional_block) except RuleNotConditional: return None elif role == Qt.UserRole: return rule setools-4.4.0/setoolsgui/treeview.py000066400000000000000000000046241402045477700176300ustar00rootroot00000000000000# Copyright 2016, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt, QModelIndex from PyQt5.QtGui import QKeySequence, QCursor from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMenu, QTreeWidget, \ QTreeWidgetItemIterator class SEToolsTreeWidget(QTreeWidget): """QTreeWidget class extended for SETools use.""" def __init__(self, parent): super(SEToolsTreeWidget, self).__init__(parent) # set up right-click context menu self.copy_tree_action = QAction("Copy Tree...", self) self.menu = QMenu(self) self.menu.addAction(self.copy_tree_action) # connect signals self.copy_tree_action.triggered.connect(self.copy_tree) def contextMenuEvent(self, event): self.menu.popup(QCursor.pos()) def copy_tree(self): """Copy the tree to the clipboard.""" items = [] inval_index = QModelIndex() it = QTreeWidgetItemIterator(self) prev_depth = 0 while it.value(): depth = 0 item = it.value() parent = item.parent() while parent: depth += 1 parent = parent.parent() if depth < prev_depth: items.extend([" |" * depth, "\n"]) if depth: items.extend([" |" * depth, "--", item.text(0), "\n"]) else: items.extend([item.text(0), "\n"]) prev_depth = depth it += 1 QApplication.clipboard().setText("".join(items)) def event(self, e): if e == QKeySequence.Copy or e == QKeySequence.Cut: self.copy_tree() return True else: return super(SEToolsTreeWidget, self).event(e) setools-4.4.0/setoolsgui/typeattrmodel.py000066400000000000000000000036231402045477700206710ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def typeattr_detail(parent, attr): """ Create a dialog box for attribute details. Parameters: parent The parent Qt Widget role The role """ detail = DetailsPopup(parent, "Type attribute detail: {0}".format(attr)) types = sorted(attr.expand()) detail.append_header("Types ({0}): ".format(len(types))) for t in types: detail.append(" {0}".format(t)) detail.show() class TypeAttributeTableModel(SEToolsTableModel): """Table-based model for roles.""" headers = ["Name", "Types"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: return ", ".join(sorted(t.name for t in item.expand())) elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/typemodel.py000066400000000000000000000045561402045477700200040ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt from PyQt5.QtGui import QPalette, QTextCursor from setools.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def type_detail(parent, type_): """ Create a dialog box for type details. Parameters: parent The parent Qt Widget type_ The type """ detail = DetailsPopup(parent, "Type detail: {0}".format(type_)) detail.append_header("Permissive: {0}\n".format("Yes" if type_.ispermissive else "No")) attrs = sorted(type_.attributes()) detail.append_header("Attributes ({0}):".format(len(attrs))) for a in attrs: detail.append(" {0}".format(a)) aliases = sorted(type_.aliases()) detail.append_header("\nAliases ({0}):".format(len(aliases))) for a in aliases: detail.append(" {0}".format(a)) detail.show() class TypeTableModel(SEToolsTableModel): """Table-based model for types.""" headers = ["Name", "Attributes", "Aliases", "Permissive"] def data(self, index, role): if self.resultlist and index.isValid(): row = index.row() col = index.column() item = self.resultlist[row] if role == Qt.DisplayRole: if col == 0: return item.name elif col == 1: return ", ".join(sorted(a.name for a in item.attributes())) elif col == 2: return ", ".join(sorted(a for a in item.aliases())) elif col == 3 and item.ispermissive: return "Permissive" elif role == Qt.UserRole: return item setools-4.4.0/setoolsgui/usermodel.py000066400000000000000000000053651402045477700200000ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from PyQt5.QtCore import Qt, QModelIndex from setools.exception import MLSDisabled from .details import DetailsPopup from .models import SEToolsTableModel def user_detail(parent, user): """ Create a dialog box for user details. Parameters: parent The parent Qt Widget user The user """ detail = DetailsPopup(parent, "User detail: {0}".format(user)) roles = sorted(user.roles) detail.append_header("Roles ({0}):".format(len(roles))) for role in roles: detail.append(" {0}".format(role)) try: level = user.mls_level range_ = user.mls_range except MLSDisabled: pass else: detail.append_header("\nDefault MLS Level:") detail.append(" {0}".format(level)) detail.append_header("\nMLS Range:") detail.append(" {0}".format(range_)) detail.show() class UserTableModel(SEToolsTableModel): """Table-based model for users.""" headers = ["Name", "Roles", "Default Level", "Range"] def __init__(self, parent, mls): super(UserTableModel, self).__init__(parent) self.col_count = 4 if mls else 2 def columnCount(self, parent=QModelIndex()): return self.col_count def data(self, index, role): if self.resultlist and index.isValid(): if role == Qt.DisplayRole: row = index.row() col = index.column() user = self.resultlist[row] if col == 0: return user.name elif col == 1: return ", ".join(sorted(r.name for r in user.roles)) elif col == 2: try: return str(user.mls_level) except MLSDisabled: return None elif col == 3: try: return str(user.mls_range) except MLSDisabled: return None elif role == Qt.UserRole: return user setools-4.4.0/setoolsgui/widget.py000066400000000000000000000024371402045477700172610ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import sys from errno import ENOENT import pkg_resources from PyQt5.uic import loadUi # Stylesheet that adds a frame around QGroupBoxes stylesheet = "\ QGroupBox {\ border: 1px solid lightgrey;\ margin-top: 0.5em;\ }\ \ QGroupBox::title {\ subcontrol-origin: margin;\ left: 10px;\ padding: 0 3px 0 3px;\ }\ " class SEToolsWidget: def load_ui(self, filename): distro = pkg_resources.get_distribution("setools") path = "{0}/setoolsgui/{1}".format(distro.location, filename) loadUi(path, self) self.setStyleSheet(stylesheet) setools-4.4.0/setup.py000066400000000000000000000143531402045477700147410ustar00rootroot00000000000000#!/usr/bin/env python3 import glob from setuptools import setup import distutils.log as log from distutils.core import Extension from distutils.cmd import Command from distutils.command.clean import clean import subprocess import sys import os import shutil from os.path import join from itertools import chain from contextlib import suppress from Cython.Build import cythonize import os.path class CleanCommand(clean): """ Extend the clean command to clean cython and Qt files. This will clean the .c intermediate file, and if --all is specified, will remove __pycache__ and Qt help files. """ def run(self): extensions_to_remove = [".so", ".c"] files_to_remove = [] dirs_to_remove = ["setools.egg-info"] if self.all: # --all includes Qt help files self.announce("Cleaning __pycache__ dirs and Qt help files", level=log.INFO) extensions_to_remove.extend((".qhc", ".qch")) # collect files and dirs to delete for root, dirs, files in chain(os.walk("setools"), os.walk("setoolsgui"), os.walk("tests"), os.walk("qhc")): for f in files: if os.path.splitext(f)[-1] in extensions_to_remove: files_to_remove.append(join(root, f)) for d in dirs: if d == "__pycache__" and self.all: dirs_to_remove.append(join(root, d)) for file in files_to_remove: with suppress(Exception): os.unlink(file) for dir_ in dirs_to_remove: with suppress(Exception): shutil.rmtree(dir_, ignore_errors=True) clean.run(self) class QtHelpCommand(Command): description = "Build Qt help files." user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): command = ['qcollectiongenerator', 'qhc/apol.qhcp'] self.announce("Building Qt help files", level=log.INFO) self.announce(' '.join(command), level=log.INFO) subprocess.check_call(command) self.announce("Moving Qt help files to setoolsgui/apol") os.rename('qhc/apol.qhc', 'setoolsgui/apol/apol.qhc') os.rename('qhc/apol.qch', 'setoolsgui/apol/apol.qch') # Library linkage lib_dirs = ['.', '/usr/lib64', '/usr/lib', '/usr/local/lib'] include_dirs = [] with suppress(KeyError): userspace_src = os.environ["USERSPACE_SRC"] include_dirs.insert(0, userspace_src + "/libsepol/include") include_dirs.insert(1, userspace_src + "/libselinux/include") lib_dirs.insert(0, userspace_src + "/libsepol/src") lib_dirs.insert(1, userspace_src + "/libselinux/src") if sys.platform.startswith('darwin'): macros=[('DARWIN',1)] else: macros=[] # Code coverage. Enable this to get coverage in the cython code. enable_coverage = bool(os.environ.get("SETOOLS_COVERAGE", False)) if enable_coverage: macros.append(("CYTHON_TRACE", 1)) cython_annotate = bool(os.environ.get("SETOOLS_ANNOTATE", False)) ext_py_mods = [Extension('setools.policyrep', ['setools/policyrep.pyx'], include_dirs=include_dirs, libraries=['selinux', 'sepol'], library_dirs=lib_dirs, define_macros=macros, extra_compile_args=['-Wextra', '-Waggregate-return', '-Wfloat-equal', '-Wformat', '-Wformat=2', '-Winit-self', '-Wmissing-format-attribute', '-Wmissing-include-dirs', '-Wnested-externs', '-Wold-style-definition', '-Wpointer-arith', '-Wstrict-prototypes', '-Wunknown-pragmas', '-Wwrite-strings', '-fno-exceptions'])] installed_data = [('share/man/man1', glob.glob("man/*.1"))] linguas = ["ru"] with suppress(KeyError): linguas = os.environ["LINGUAS"].split(" ") for lang in linguas: if lang and os.path.exists(join("man", lang)): installed_data.append((join('share/man', lang, 'man1'), glob.glob(join("man", lang, "*.1")))) setup(name='setools', version='4.4.0', description='SELinux policy analysis tools.', author='Chris PeBenito', author_email='pebenito@ieee.org', url='https://github.com/SELinuxProject/setools', cmdclass={'build_qhc': QtHelpCommand, 'clean': CleanCommand}, packages=['setools', 'setools.checker', 'setools.diff', 'setoolsgui', 'setoolsgui.apol'], scripts=['apol', 'sediff', 'seinfo', 'seinfoflow', 'sesearch', 'sedta', 'sechecker'], data_files=installed_data, package_data={'': ['*.ui', '*.qhc', '*.qch'], 'setools': ['perm_map']}, ext_modules=cythonize(ext_py_mods, include_path=['setools/policyrep'], annotate=cython_annotate, compiler_directives={"language_level": 3, "c_string_type": "str", "c_string_encoding": "ascii", "linetrace": enable_coverage}), test_suite='tests', license='GPLv2+, LGPLv2.1+', classifiers=[ 'Environment :: Console', 'Environment :: X11 Applications :: Qt', 'Intended Audience :: Information Technology', 'Topic :: Security', 'Topic :: Utilities', ], keywords='SELinux SETools policy analysis tools seinfo sesearch sediff sedta seinfoflow apol', python_requires='>=3.4', # setup also requires libsepol and libselinux # C libraries and headers to compile. setup_requires=['setuptools', 'Cython>=0.27'], install_requires=['setuptools', 'networkx>=2.0'] ) setools-4.4.0/tests/000077500000000000000000000000001402045477700143635ustar00rootroot00000000000000setools-4.4.0/tests/__init__.py000066400000000000000000000026561402045477700165050ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # from . import boolquery from . import boundsquery from . import categoryquery from . import checker from . import constraintquery from . import commonquery from . import defaultquery from . import diff from . import dta from . import fsusequery from . import genfsconquery from . import ibendportconquery from . import ibpkeyconquery from . import infoflow from . import initsidquery from . import mlsrulequery from . import netifconquery from . import nodeconquery from . import objclassquery from . import permmap from . import polcapquery from . import policyrep from . import rbacrulequery from . import rolequery from . import sensitivityquery from . import terulequery from . import typeattrquery from . import typequery from . import userquery setools-4.4.0/tests/boolquery.conf000066400000000000000000000043641402045477700172620ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # Booleans Query # # test 1 # name: test1 # default: unset bool test1 true; # test 2 # name: test2(a|b) regex # default: unset bool test2a true; bool test2b true; # test 10 # name: unset # default: false; bool test10a false; bool test10b false; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/boolquery.py000066400000000000000000000040211402045477700167530ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import BoolQuery from .policyrep.util import compile_policy class BoolQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/boolquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Boolean query with no criteria.""" # query with no parameters gets all Booleans. allbools = sorted(str(b) for b in self.p.bools()) q = BoolQuery(self.p) qbools = sorted(str(b) for b in q.results()) self.assertListEqual(allbools, qbools) def test_001_name_exact(self): """Boolean query with exact match""" q = BoolQuery(self.p, name="test1") bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test1"], bools) def test_002_name_regex(self): """Boolean query with regex match.""" q = BoolQuery(self.p, name="test2(a|b)", name_regex=True) bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test2a", "test2b"], bools) def test_010_default(self): """Boolean query with default state match.""" q = BoolQuery(self.p, default=False) bools = sorted(str(b) for b in q.results()) self.assertListEqual(["test10a", "test10b"], bools) setools-4.4.0/tests/boundsquery.conf000066400000000000000000000050341402045477700176140ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; # test 1 exact match parent type test1_parent; type test1_child; typebounds test1_parent test1_child; # test 2 regex match parent type test2_parent1; type test2_parent2; type test2_child1; type test2_child2; typebounds test2_parent1 test2_child2; typebounds test2_parent2 test2_child1; # test 10 exact match child type test10_parent; type test10_child; typebounds test10_parent test10_child; # test 11 regex match child type test11_parent1; type test11_parent2; type test11_child1; type test11_child2; typebounds test11_parent1 test11_child2; typebounds test11_parent2 test11_child1; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/boundsquery.py000066400000000000000000000065641402045477700173300ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import BoundsQuery, BoundsRuletype from .policyrep.util import compile_policy class BoundsQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/boundsquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Bounds query with no criteria.""" # query with no parameters gets all bounds. allbounds = sorted(self.p.bounds()) q = BoundsQuery(self.p) qbounds = sorted(q.results()) self.assertListEqual(allbounds, qbounds) def test_001_parent_exact(self): """Bounds query with exact parent match.""" q = BoundsQuery(self.p, parent="test1_parent", parent_regex=False) qbounds = sorted(q.results()) self.assertEqual(1, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test1_parent", b.parent) self.assertEqual("test1_child", b.child) def test_002_parent_regex(self): """Bounds query with regex parent match.""" q = BoundsQuery(self.p, parent="test2_parent?", parent_regex=True) qbounds = sorted(q.results()) self.assertEqual(2, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test2_parent1", b.parent) self.assertEqual("test2_child2", b.child) b = qbounds[1] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test2_parent2", b.parent) self.assertEqual("test2_child1", b.child) def test_010_child_exact(self): """Bounds query with exact child match.""" q = BoundsQuery(self.p, child="test10_child", child_regex=False) qbounds = sorted(q.results()) self.assertEqual(1, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test10_parent", b.parent) self.assertEqual("test10_child", b.child) def test_011_child_regex(self): """Bounds query with regex child match.""" q = BoundsQuery(self.p, child="test11_child?", child_regex=True) qbounds = sorted(q.results()) self.assertEqual(2, len(qbounds)) b = qbounds[0] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test11_parent1", b.parent) self.assertEqual("test11_child2", b.child) b = qbounds[1] self.assertEqual(BoundsRuletype.typebounds, b.ruletype) self.assertEqual("test11_parent2", b.parent) self.assertEqual("test11_child1", b.child) setools-4.4.0/tests/categoryquery.conf000066400000000000000000000043501402045477700201370ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity sens; dominance { sens } category begin; # test1 # name: test1 # alias: unset category test1; # test2 # name: test2(a|b) # alias: unset category test2a; category test2b; # test 10 # name: unset # alias: test10a category test10c1 alias { test10a test10c }; category test10c2 alias { test10b test10d }; # test 11 # name: unset # alias: test11(a|b) category test11c1 alias { test11a test11c }; category test11c2 alias { test11b test11d }; category test11c3 alias { test11e test11f }; category end; #level decl level sens:begin.end; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles system level sens range sens - sens:begin.end; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:sens:begin sid security system:system:system:sens:begin #fs_use fs_use_trans devpts system:object_r:system:sens; fs_use_xattr ext3 system:object_r:system:sens; fs_use_task pipefs system:object_r:system:sens; #genfscon genfscon proc / system:object_r:system:sens genfscon proc /sys system:object_r:system:sens genfscon selinuxfs / system:object_r:system:sens:begin.end portcon tcp 80 system:object_r:system:sens netifcon eth0 system:object_r:system:sens system:object_r:system:sens nodecon 127.0.0.1 255.255.255.255 system:object_r:system:sens:begin nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:sens:begin setools-4.4.0/tests/categoryquery.py000066400000000000000000000045331402045477700176450ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import CategoryQuery from .policyrep.util import compile_policy class CategoryQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/categoryquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """MLS category query with no criteria.""" # query with no parameters gets all categories. allcats = sorted(str(c) for c in self.p.categories()) q = CategoryQuery(self.p) qcats = sorted(str(c) for c in q.results()) self.assertListEqual(allcats, qcats) def test_001_name_exact(self): """MLS category query with exact name match.""" q = CategoryQuery(self.p, name="test1") cats = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], cats) def test_002_name_regex(self): """MLS category query with regex name match.""" q = CategoryQuery(self.p, name="test2(a|b)", name_regex=True) cats = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], cats) def test_010_alias_exact(self): """MLS category query with exact alias match.""" q = CategoryQuery(self.p, alias="test10a") cats = sorted(str(t) for t in q.results()) self.assertListEqual(["test10c1"], cats) def test_011_alias_regex(self): """MLS category query with regex alias match.""" q = CategoryQuery(self.p, alias="test11(a|b)", alias_regex=True) cats = sorted(str(t) for t in q.results()) self.assertListEqual(["test11c1", "test11c2"], cats) setools-4.4.0/tests/checker/000077500000000000000000000000001402045477700157675ustar00rootroot00000000000000setools-4.4.0/tests/checker/__init__.py000066400000000000000000000015311402045477700201000ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # from . import assertrbac from . import assertte from . import checker from . import emptyattr from . import roexec from . import util setools-4.4.0/tests/checker/assertrbac.conf000066400000000000000000000060001402045477700207630ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type test1a; type test1b; allow test1a test1b:infoflow hi_w; ################################################################################ # Roles for config tests: role src; role tgt; role exempt_src1; role exempt_tgt1; role exempt_src2; role exempt_tgt2; role exempt_source_role; role exempt_target_role; # pass, exempt source role source1; role target1; allow source1 target1; # pass, exempt target role source2; role target2; allow source2 target2; # pass, expect source role source3a; role source3b; role target3; allow source3a target3; allow source3b target3; # pass, expect target role source4; role target4a; role target4b; allow source4 target4a; allow source4 target4b; # pass, expected and exempt sources role source5a; role source5b; role target5; allow source5a target5; allow source5b target5; # pass, expected and exempt targets role source6; role target6a; role target6b; allow source6 target6a; allow source6 target6b; # fail role source7; role target7a; role target7b; role target7c; allow source7 target7a; allow source7 target7b; allow source7 target7c; # fail, expect source role source8; role target8; # fail, expect target role source9; role target9; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/checker/assertrbac.py000066400000000000000000000241441402045477700204770ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # Copyright 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import unittest from ..policyrep.util import compile_policy from setools import RBACRuletype from setools.checker.assertrbac import AssertRBAC from setools.exception import InvalidCheckValue, InvalidCheckOption class AssertRBACTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/checker/assertrbac.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_unconfigured(self): """Test unconfigured.""" with self.assertRaises(InvalidCheckValue): config = {} check = AssertRBAC(self.p, "test_unconfigured", config) def test_invalid_option(self): """Test invalid option""" with self.assertRaises(InvalidCheckOption): config = {"INVALID": "option"} check = AssertRBAC(self.p, "test_invalid_option", config) def test_source(self): """Test source setting.""" with self.subTest("Success"): config = {"source": "src"} check = AssertRBAC(self.p, "test_source", config) expected = self.p.lookup_role("src") self.assertEqual(expected, check.source) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"source": "FAIL"} check = AssertRBAC(self.p, "test_source_fail", config) def test_target(self): """Test target setting.""" with self.subTest("Success"): config = {"target": "tgt"} check = AssertRBAC(self.p, "test_target", config) expected = self.p.lookup_role("tgt") self.assertEqual(expected, check.target) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"target": "FAIL2"} check = AssertRBAC(self.p, "test_target_fail", config) def test_exempt_source(self): """Test exempt_source setting.""" with self.subTest("Success"): config = {"source": "system", "exempt_source": " exempt_src1 exempt_src2 "} check = AssertRBAC(self.p, "test_exempt_source", config) # exempt_src2 is an attr expected = set((self.p.lookup_role("exempt_src1"), self.p.lookup_role("exempt_src2"))) self.assertIsInstance(check.exempt_source, frozenset) self.assertSetEqual(expected, check.exempt_source) with self.subTest("Success, missing role ignored"): """Test exempt_source missing role is ignroed.""" config = {"source": "system", "exempt_source": "FAIL exempt_src2"} check = AssertRBAC(self.p, "test_source_missing_ignored", config) # exempt_src2 is an attr expected = set((self.p.lookup_role("exempt_src2"),)) self.assertIsInstance(check.exempt_source, frozenset) self.assertSetEqual(expected, check.exempt_source) def test_exempt_target(self): """Test exempt_target setting.""" with self.subTest("Success"): config = {"target": "system", "exempt_target": " exempt_tgt1 exempt_tgt2 "} check = AssertRBAC(self.p, "test_exempt_target", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_role("exempt_tgt1"), self.p.lookup_role("exempt_tgt2"))) self.assertIsInstance(check.exempt_target, frozenset) self.assertSetEqual(expected, check.exempt_target) with self.subTest("Success, missing role ignored"): config = {"target": "system", "exempt_target": "FAIL exempt_tgt2"} check = AssertRBAC(self.p, "test_target_missing_ignored", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_role("exempt_tgt2"),)) self.assertIsInstance(check.exempt_target, frozenset) self.assertSetEqual(expected, check.exempt_target) def test_expect_source(self): """Test expect_source setting.""" with self.subTest("Success"): config = {"target": "tgt", "expect_source": " exempt_src1 exempt_src2 "} check = AssertRBAC(self.p, "test_expect_source", config) # exempt_src2 is an attr expected = set((self.p.lookup_role("exempt_src1"), self.p.lookup_role("exempt_src2"))) self.assertIsInstance(check.expect_source, frozenset) self.assertSetEqual(expected, check.expect_source) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"target": "tgt", "expect_source": " source1 INVALID "} check = AssertRBAC(self.p, "test_expect_source_fail", config) def test_expect_target(self): """Test expect_target setting.""" with self.subTest("Success"): config = {"source": "src", "expect_target": " exempt_tgt1 exempt_tgt2 "} check = AssertRBAC(self.p, "test_expect_target", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_role("exempt_tgt1"), self.p.lookup_role("exempt_tgt2"))) self.assertIsInstance(check.expect_target, frozenset) self.assertSetEqual(expected, check.expect_target) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"source": "src", "expect_target": " target1 INVALID "} check = AssertRBAC(self.p, "test_expect_target_fail", config) def test_check_passes(self): """Test the check passes, no matches""" config = {"source": "src", "target": "tgt"} check = AssertRBAC(self.p, "test_check_passes", config) self.assertFalse(check.run()) def test_check_passes_exempt_source_role(self): """Test the check passes, exempt_source_role""" config = {"target": "target1", "exempt_source": "source1"} check = AssertRBAC(self.p, "test_check_passes_exempt_source_role", config) self.assertFalse(check.run()) def test_check_passes_exempt_target_role(self): """Test the check passes, exempt_target_role""" config = {"target": "target2", "exempt_source": "source2"} check = AssertRBAC(self.p, "test_check_passes_exempt_target_role", config) self.assertFalse(check.run()) def test_check_passes_expect_source(self): """Test the check passes, expect_source""" config = {"target": "target3", "expect_source": "source3a source3b"} check = AssertRBAC(self.p, "test_check_passes_expect_source", config) self.assertFalse(check.run()) def test_check_passes_expect_target(self): """Test the check passes, expect_target""" config = {"source": "source4", "expect_target": "target4a target4b"} check = AssertRBAC(self.p, "test_check_passes_expect_target", config) self.assertFalse(check.run()) def test_check_passes_expect_exempt_source(self): """"Test the check passes with both expected and exempted sources.""" config = {"target": "target5", "expect_source": "source5a", "exempt_source": "source5b"} check = AssertRBAC(self.p, "test_check_passes_expect_exempt_source", config) self.assertFalse(check.run()) def test_check_passes_expect_exempt_target(self): """"Test the check passes with both expected and exempted targets.""" config = {"source": "source6", "expect_target": "target6a", "exempt_target": "target6b"} check = AssertRBAC(self.p, "test_check_passes_expect_exempt_target", config) self.assertFalse(check.run()) def test_check_fails(self): """Test the check fails""" with open("/dev/null", "w") as fd: config = {"source": "source7", "expect_target": "target7a", "exempt_target": "target7b"} check = AssertRBAC(self.p, "test_check_passes_exempt_target_attr", config) check.output = fd result = check.run() self.assertEqual(1, len(result), msg=result) rule = result[0] self.assertEqual(RBACRuletype.allow, rule.ruletype) self.assertEqual("source7", rule.source) self.assertEqual("target7c", rule.target) def test_check_fails_expect_source(self): """Test the check fails, expect_source""" config = {"target": "target8", "expect_source": "source8"} check = AssertRBAC(self.p, "test_check_fails_expect_source", config) result = check.run() self.assertEqual(1, len(result), msg=result) self.assertIn("source8", result[0]) def test_check_fails_expect_target(self): """Test the check fails, expect_target""" config = {"source": "source9", "expect_target": "target9"} check = AssertRBAC(self.p, "test_check_fails_expect_target", config) result = check.run() self.assertEqual(1, len(result), msg=result) self.assertIn("target9", result[0]) setools-4.4.0/tests/checker/assertte.conf000066400000000000000000000061151402045477700204730ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type test1a; type test1b; allow test1a test1b:infoflow hi_w; ################################################################################ # Types for config tests: type src; type tgt; type exempt_src1; type exempt_tgt1; attribute exempt_src2; type exempt_source_type, exempt_src2; attribute exempt_tgt2; type exempt_target_type, exempt_tgt2; # Rules for run tests: attribute all_sources; type source1, all_sources; type source2, all_sources; type source3, all_sources; attribute all_targets; type target1, all_targets; type target2, all_targets; type target3, all_targets; attribute empty_source; attribute empty_target; # empty attr passing: allow empty_source target1:infoflow7 super_w; allow source2 empty_target:infoflow7 super_r; # pass by exemption, explicit type source allow source1 target1:infoflow6 hi_w; # pass by exemption, attribute source allow source1 target1:infoflow6 hi_r; allow source2 target2:infoflow6 hi_r; # pass by exemption, explicit type target allow source1 target2:infoflow5 low_w; # pass by exemption, attribute target allow source1 target1:infoflow5 low_r; allow source2 target2:infoflow5 low_r; # fail allow source1 target1:infoflow4 med_w; allow source2 target2:infoflow4 med_w; allow source3 target3:infoflow4 med_w; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/checker/assertte.py000066400000000000000000000323141402045477700201760ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # Copyright 2020, Chris PeBenito # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import logging import unittest from .. import mixins from ..policyrep.util import compile_policy from setools import TERuletype from setools.checker.assertte import AssertTE from setools.exception import InvalidCheckValue, InvalidCheckOption class AssertTETest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/checker/assertte.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_unconfigured(self): """Test unconfigured.""" with self.assertRaises(InvalidCheckValue): config = {} check = AssertTE(self.p, "test_unconfigured", config) def test_invalid_option(self): """Test invalid option""" with self.assertRaises(InvalidCheckOption): config = {"INVALID": "option"} check = AssertTE(self.p, "test_invalid_option", config) def test_source(self): """Test source setting.""" config = {"source": "src"} check = AssertTE(self.p, "test_source", config) expected = self.p.lookup_type("src") self.assertEqual(expected, check.source) def test_source_fail(self): """Test source setting failure.""" with self.assertRaises(InvalidCheckValue): config = {"source": "FAIL"} check = AssertTE(self.p, "test_source_fail", config) def test_target(self): """Test target setting.""" config = {"target": "tgt"} check = AssertTE(self.p, "test_target", config) expected = self.p.lookup_type("tgt") self.assertEqual(expected, check.target) def test_target_fail(self): """Test target setting failure.""" with self.assertRaises(InvalidCheckValue): config = {"target": "FAIL2"} check = AssertTE(self.p, "test_target_fail", config) def test_exempt_source(self): """Test exempt_source setting.""" config = {"source": "system", "exempt_source": " exempt_src1 exempt_src2 "} check = AssertTE(self.p, "test_exempt_source", config) # exempt_src2 is an attr expected = set((self.p.lookup_type("exempt_src1"), self.p.lookup_type("exempt_source_type"))) self.assertIsInstance(check.exempt_source, frozenset) self.assertSetEqual(expected, check.exempt_source) def test_source_missing_ignored(self): """Test exempt_source missing type is ignroed.""" config = {"source": "system", "exempt_source": "FAIL exempt_src2"} check = AssertTE(self.p, "test_source_missing_ignored", config) # exempt_src2 is an attr expected = set((self.p.lookup_type("exempt_source_type"),)) self.assertIsInstance(check.exempt_source, frozenset) self.assertSetEqual(expected, check.exempt_source) def test_exempt_target(self): """Test exempt_target setting.""" config = {"target": "system", "exempt_target": " exempt_tgt1 exempt_tgt2 "} check = AssertTE(self.p, "test_exempt_target", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_type("exempt_tgt1"), self.p.lookup_type("exempt_target_type"))) self.assertIsInstance(check.exempt_target, frozenset) self.assertSetEqual(expected, check.exempt_target) def test_target_missing_ignored(self): """Test exempt_target missing type is ignroed.""" config = {"target": "system", "exempt_target": "FAIL exempt_tgt2"} check = AssertTE(self.p, "test_target_missing_ignored", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_type("exempt_target_type"),)) self.assertIsInstance(check.exempt_target, frozenset) self.assertSetEqual(expected, check.exempt_target) def test_expect_source(self): """Test expect_source setting.""" with self.subTest("Success"): config = {"tclass": "infoflow3", "expect_source": " exempt_src1 exempt_src2 "} check = AssertTE(self.p, "test_expect_source", config) # exempt_src2 is an attr expected = set((self.p.lookup_type("exempt_src1"), self.p.lookup_type("exempt_source_type"))) self.assertIsInstance(check.expect_source, frozenset) self.assertSetEqual(expected, check.expect_source) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"tclass": "infoflow3", "expect_source": " source1 INVALID "} check = AssertTE(self.p, "test_expect_source_fail", config) def test_expect_target(self): """Test expect_target setting.""" with self.subTest("Success"): config = {"tclass": "infoflow3", "expect_target": " exempt_tgt1 exempt_tgt2 "} check = AssertTE(self.p, "test_expect_target", config) # exempt_tgt2 is an attr expected = set((self.p.lookup_type("exempt_tgt1"), self.p.lookup_type("exempt_target_type"))) self.assertIsInstance(check.expect_target, frozenset) self.assertSetEqual(expected, check.expect_target) with self.subTest("Failure"): with self.assertRaises(InvalidCheckValue): config = {"tclass": "infoflow3", "expect_target": " target1 INVALID "} check = AssertTE(self.p, "test_expect_target_fail", config) def test_tclass(self): """Test tclass setting.""" config = {"tclass": "infoflow3 infoflow2"} check = AssertTE(self.p, "test_tclass", config) expected = set((self.p.lookup_class("infoflow3"), self.p.lookup_class("infoflow2"))) self.assertEqual(expected, check.tclass) def test_tclass_fail(self): """Test tclass setting failure.""" with self.assertRaises(InvalidCheckValue): config = {"tclass": "FAIL_class"} check = AssertTE(self.p, "test_tclass_fail", config) def test_perms(self): """Test perms setting.""" config = {"perms": " hi_w super_r "} check = AssertTE(self.p, "test_perms", config) expected = set(("hi_w", "super_r")) self.assertEqual(expected, check.perms) def test_perms_fail(self): """Test perms setting failure.""" with self.assertRaises(InvalidCheckValue): config = {"perms": "FAIL_perms"} check = AssertTE(self.p, "test_perms_fail", config) def test_check_passes(self): """Test the check passes, no matches""" config = {"perms": "null"} check = AssertTE(self.p, "test_check_passes", config) self.assertFalse(check.run()) def test_check_passes_empty_source(self): """Test the check passes, empty source attribute""" config = {"tclass": "infoflow7", "perms": "super_w"} check = AssertTE(self.p, "test_check_passes_empty_source", config) self.assertFalse(check.run()) def test_check_passes_empty_target(self): """Test the check passes, empty target attribute""" config = {"tclass": "infoflow7", "perms": "super_r"} check = AssertTE(self.p, "test_check_passes_empty_target", config) self.assertFalse(check.run()) def test_check_passes_exempt_source_type(self): """Test the check passes, exempt_source_type""" config = {"tclass": "infoflow6", "perms": "hi_w", "exempt_source": "source1"} check = AssertTE(self.p, "test_check_passes_exempt_source_type", config) self.assertFalse(check.run()) def test_check_passes_exempt_source_attr(self): """Test the check passes, exempt_source_attr""" config = {"tclass": "infoflow6", "perms": "hi_r", "exempt_source": "all_sources"} check = AssertTE(self.p, "test_check_passes_exempt_source_attr", config) self.assertFalse(check.run()) def test_check_passes_exempt_target_type(self): """Test the check passes, exempt_target_type""" config = {"tclass": "infoflow5", "perms": "low_w", "exempt_source": "source1"} check = AssertTE(self.p, "test_check_passes_exempt_target_type", config) self.assertFalse(check.run()) def test_check_passes_exempt_target_attr(self): """Test the check passes, exempt_target_attr""" config = {"tclass": "infoflow5", "perms": "low_r", "exempt_target": "all_targets"} check = AssertTE(self.p, "test_check_passes_exempt_target_attr", config) self.assertFalse(check.run()) def test_check_passes_expect_source(self): """Test the check passes, expect_source""" config = {"tclass": "infoflow6", "perms": "hi_r", "expect_source": "source1 source2"} check = AssertTE(self.p, "test_check_passes_expect_source", config) self.assertFalse(check.run()) def test_check_passes_expect_source_attr(self): """Test the check passes, expect_source with attribute""" config = {"tclass": "infoflow4", "perms": "med_w", "expect_source": "all_sources"} check = AssertTE(self.p, "test_check_passes_expect_source_attr", config) self.assertFalse(check.run()) def test_check_passes_expect_target(self): """Test the check passes, expect_target""" config = {"tclass": "infoflow6", "perms": "hi_r", "expect_target": "target1 target2"} check = AssertTE(self.p, "test_check_passes_expect_target", config) self.assertFalse(check.run()) def test_check_passes_expect_target_attr(self): """Test the check passes, expect_target with attribute""" config = {"tclass": "infoflow4", "perms": "med_w", "expect_target": "all_targets"} check = AssertTE(self.p, "test_check_passes_expect_target_attr", config) self.assertFalse(check.run()) def test_check_passes_expect_exempt_source(self): """"Test the check passes with both expected and exempted sources.""" config = {"tclass": "infoflow5", "perms": "low_r", "expect_source": "source1", "exempt_source": "source2"} check = AssertTE(self.p, "test_check_passes_expect_exempt_source", config) self.assertFalse(check.run()) def test_check_passes_expect_exempt_target(self): """"Test the check passes with both expected and exempted targets.""" config = {"tclass": "infoflow5", "perms": "low_r", "expect_source": "source1", "exempt_source": "source2"} check = AssertTE(self.p, "test_check_passes_expect_exempt_target", config) self.assertFalse(check.run()) def test_check_fails(self): """Test the check fails""" with open("/dev/null", "w") as fd: config = {"tclass": "infoflow4", "perms": "med_w", "exempt_source": "source1", "exempt_target": "target2"} check = AssertTE(self.p, "test_check_passes_exempt_target_attr", config) check.output = fd result = check.run() self.assertEqual(1, len(result), msg=result) self.validate_rule(result[0], TERuletype.allow, "source3", "target3", "infoflow4", set(["med_w"])) def test_check_fails_expect_source(self): """Test the check fails, expect_source""" config = {"tclass": "infoflow7", "perms": "super_w", "expect_source": "source1"} check = AssertTE(self.p, "test_check_fails_expect_source", config) result = check.run() self.assertEqual(1, len(result), msg=result) self.assertIn("source1", result[0]) def test_check_fails_expect_target(self): """Test the check fails, expect_target""" config = {"tclass": "infoflow7", "perms": "super_r", "expect_target": "target2"} check = AssertTE(self.p, "test_check_fails_expect_target", config) result = check.run() self.assertEqual(1, len(result), msg=result) self.assertIn("target2", result[0]) setools-4.4.0/tests/checker/checker-invalidoption.ini000066400000000000000000000001711402045477700227500ustar00rootroot00000000000000[emptyattr] desc = empty type attribute test check_type = empty_typeattr attr = empty_source_attr invalid_option = value setools-4.4.0/tests/checker/checker-invalidtype.ini000066400000000000000000000000771402045477700224260ustar00rootroot00000000000000[emptyattr] check_type = invalid_type attr = empty_source_attr setools-4.4.0/tests/checker/checker-invalidvalue.ini000066400000000000000000000000671402045477700225600ustar00rootroot00000000000000[emptyattr] check_type = empty_typeattr attr = INVALID setools-4.4.0/tests/checker/checker-missingtype.ini000066400000000000000000000000451402045477700224440ustar00rootroot00000000000000[emptyattr] attr = empty_source_attr setools-4.4.0/tests/checker/checker-valid.ini000066400000000000000000000004451402045477700211740ustar00rootroot00000000000000[emptyattr] desc = empty type attribute test check_type = empty_typeattr attr = empty_source_attr [roexec] desc = read only executables test check_type = ro_execs exempt_exec_domain = unconfined exempt_write_domain = domain1 domain2 unconfined [assertte] check_type = assert_te perms = null setools-4.4.0/tests/checker/checker.conf000066400000000000000000000057731402045477700202560ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class file sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class file { read write append execute execute_no_trans } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules attribute domain; type domain1, domain; type domain2, domain; type unconfined, domain; attribute empty_source_attr; attribute empty_target_attr; attribute files; attribute exempt_files_attr; type exempt_file, files; type execfile1, files, exempt_files_attr; type execfile2, files, exempt_files_attr; # Baseline read-only executable: type roexec, files; allow domain roexec:file { read execute execute_no_trans }; # Baseline non-executable file (executable due to unconfined): type nonexec, files; allow domain nonexec:file read; # Unconfined allow unconfined files:file { read write append execute execute_no_trans }; # writer allow domain1 execfile1:file write; allow domain2 execfile1:file { read execute execute }; # appender allow domain2 execfile2:file append; allow domain1 execfile2:file { read execute execute }; # empty attrs allow empty_source_attr nonexec:file { read write append execute execute_no_trans }; allow domain1 empty_target_attr:file { read write append execute execute_no_trans }; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/checker/checker.py000066400000000000000000000071021402045477700177450ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import unittest from unittest.mock import Mock from ..policyrep.util import compile_policy from setools.checker import PolicyChecker from setools.exception import InvalidCheckerConfig, InvalidCheckerModule, InvalidCheckOption, \ InvalidCheckValue class PolicyCheckerTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/checker/checker.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_config_empty(self): """Test empty config file""" with self.assertRaises(InvalidCheckerConfig): PolicyChecker(self.p, "/dev/null") def test_config_check_missing_type(self): """Test check missing check type""" with self.assertRaises(InvalidCheckerModule): PolicyChecker(self.p, "tests/checker/checker-missingtype.ini") def test_config_check_invalid_type(self): """Test check invalid check type""" with self.assertRaises(InvalidCheckerModule): PolicyChecker(self.p, "tests/checker/checker-invalidtype.ini") def test_config_check_invalid_option(self): """Test check invalid check option""" with self.assertRaises(InvalidCheckOption): PolicyChecker(self.p, "tests/checker/checker-invalidoption.ini") def test_config_check_invalid_value(self): """Test check invalid check type""" with self.assertRaises(InvalidCheckValue): PolicyChecker(self.p, "tests/checker/checker-invalidvalue.ini") def test_run_pass(self): """Test run with passing config.""" with open(os.devnull, "w") as fd: checker = PolicyChecker(self.p, "tests/checker/checker-valid.ini") # create additional disabled mock test newcheck = Mock() newcheck.checkname = "disabled" newcheck.disable = True newcheck.validate_config.return_value = None newcheck.run.return_value = [] checker.checks.append(newcheck) self.assertEqual(4, len(checker.checks)) result = checker.run(output=fd) self.assertEqual(0, result) newcheck.run.assert_not_called() def test_run_fail(self): """Test run with failing config.""" with open(os.devnull, "w") as fd: checker = PolicyChecker(self.p, "tests/checker/checker-valid.ini") # create additional failing mock test newcheck = Mock() newcheck.checkname = "failing test" newcheck.disable = False newcheck.validate_config.return_value = None newcheck.run.return_value = list(range(13)) checker.checks.append(newcheck) self.assertEqual(4, len(checker.checks)) result = checker.run(output=fd) newcheck.run.assert_called() self.assertEqual(13, result) setools-4.4.0/tests/checker/emptyattr.conf000066400000000000000000000041441402045477700206720ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; # Test 1: success: attribute test1; # Test 2: success by missing # Test 3: fail attribute test3; type test3_hit1, test3; type test3_hit2, test3; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/checker/emptyattr.py000066400000000000000000000103501402045477700203710ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import unittest from ..policyrep.util import compile_policy from setools.checker.emptyattr import EmptyTypeAttr from setools.exception import InvalidCheckOption, InvalidCheckValue class EmptyTypeAttrTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/checker/emptyattr.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_invalid_option(self): """Test invalid option""" with self.assertRaises(InvalidCheckOption): config = {"INVALID": "option"} check = EmptyTypeAttr(self.p, "test_invalid_option", config) def test_attr_setting(self): """EmptyTypeAttr test attr setting.""" config = {"attr": "test1"} check = EmptyTypeAttr(self.p, "test_attr_setting", config) expected = self.p.lookup_typeattr("test1") self.assertEqual(expected, check.attr) def test_attr_setting_fail(self): """EmptyTypeAttr test attr setting with invalid attr.""" with self.assertRaises(InvalidCheckValue): config = {"attr": "FAILATTR"} check = EmptyTypeAttr(self.p, "test_attr_setting_fail", config) def test_attr_setting_missing(self): """EmptyTypeAttr test attr setting missing.""" with self.assertRaises(InvalidCheckValue): config = {} check = EmptyTypeAttr(self.p, "test_attr_setting_missing", config) def test_missingok_setting(self): """EmptyTypeAttr test missing_ok setting.""" config = {"attr": "test1", "missing_ok": "true"} check = EmptyTypeAttr(self.p, "test_missingok_setting", config) self.assertTrue(check.missing_ok) config = {"attr": "test1", "missing_ok": " YeS "} check = EmptyTypeAttr(self.p, "test_missingok_setting", config) self.assertTrue(check.missing_ok) config = {"attr": "test1", "missing_ok": " 1 "} check = EmptyTypeAttr(self.p, "test_missingok_setting", config) self.assertTrue(check.missing_ok) config = {"attr": "test1", "missing_ok": " No "} check = EmptyTypeAttr(self.p, "test_missingok_setting", config) self.assertFalse(check.missing_ok) def test_pass(self): """EmptyTypeAttr test pass.""" with open("/dev/null", "w") as fd: config = {"attr": "test1"} check = EmptyTypeAttr(self.p, "test_pass", config) check.output = fd result = check.run() self.assertEqual(0, len(result)) def test_pass_missingok(self): """EmptyTypeAttr test pass by missing.""" with open("/dev/null", "w") as fd: config = {"attr": "test2", "missing_ok": "true"} check = EmptyTypeAttr(self.p, "test_pass_missingok", config) check.output = fd result = check.run() self.assertEqual(0, len(result)) def test_fail(self): """EmptyTypeAttr test fail.""" with open("/dev/null", "w") as fd: # also verify missing_ok doesn't induce a pass # when the attr exists config = {"attr": "test3", "missing_ok": "true"} check = EmptyTypeAttr(self.p, "test_fail", config) check.output = fd result = check.run() expected = [self.p.lookup_type("test3_hit1"), self.p.lookup_type("test3_hit2")] self.assertListEqual(expected, result) setools-4.4.0/tests/checker/roexec.conf000066400000000000000000000057731402045477700201370ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class file sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class file { read write append execute execute_no_trans } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules attribute domain; type domain1, domain; type domain2, domain; type unconfined, domain; attribute empty_source_attr; attribute empty_target_attr; attribute files; attribute exempt_files_attr; type exempt_file, files; type execfile1, files, exempt_files_attr; type execfile2, files, exempt_files_attr; # Baseline read-only executable: type roexec, files; allow domain roexec:file { read execute execute_no_trans }; # Baseline non-executable file (executable due to unconfined): type nonexec, files; allow domain nonexec:file read; # Unconfined allow unconfined files:file { read write append execute execute_no_trans }; # writer allow domain1 execfile1:file write; allow domain2 execfile1:file { read execute execute }; # appender allow domain2 execfile2:file append; allow domain1 execfile2:file { read execute execute }; # empty attrs allow empty_source_attr nonexec:file { read write append execute execute_no_trans }; allow domain1 empty_target_attr:file { read write append execute execute_no_trans }; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/checker/roexec.py000066400000000000000000000104251402045477700176300ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import unittest from ..policyrep.util import compile_policy from setools.checker.roexec import ReadOnlyExecutables from setools.exception import InvalidCheckOption, InvalidCheckValue class ReadOnlyExecutablesTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/checker/roexec.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_invalid_option(self): """Test invalid option""" with self.assertRaises(InvalidCheckOption): config = {"INVALID": "option"} check = ReadOnlyExecutables(self.p, "test_invalid_option", config) def test_all_exec(self): """Test all executables are returned for no-option test..""" config = {} check = ReadOnlyExecutables(self.p, "test_all_exec", config) result = check._collect_executables() # becasue of unconfined, nonexec is executable expected = set(("roexec", "execfile1", "execfile2", "nonexec", "exempt_file")) self.assertSetEqual(expected, set(result.keys())) def test_exempt_exec_domain(self): """Test for exempting an exec domain.""" config = {"exempt_exec_domain": "unconfined"} check = ReadOnlyExecutables(self.p, "test_exempt_exec_domain", config) result = check._collect_executables() expected = set(("execfile1", "execfile2", "roexec")) self.assertSetEqual(expected, set(result.keys())) def test_exempt_file(self): """Test for exempting a file.""" config = {"exempt_file": "exempt_file"} check = ReadOnlyExecutables(self.p, "test_exempt_file", config) result = check._collect_executables() expected = set(("roexec", "execfile1", "execfile2", "nonexec")) self.assertSetEqual(expected, set(result.keys())) def test_exempt_file_attr(self): """Test for exempting a file by attribute.""" config = {"exempt_file": "exempt_files_attr"} check = ReadOnlyExecutables(self.p, "test_exempt_file_attr", config) result = check._collect_executables() expected = set(("roexec", "nonexec", "exempt_file")) self.assertSetEqual(expected, set(result.keys())) def test_fail(self): """Test for failing.""" with open("/dev/null", "w") as fd: config = {"exempt_exec_domain": "unconfined", "exempt_write_domain": "unconfined"} check = ReadOnlyExecutables(self.p, "test_fail", config) check.output = fd result = check.run() expected = [self.p.lookup_type("execfile1"), self.p.lookup_type("execfile2")] self.assertListEqual(expected, result) def test_pass(self): """Test for passing.""" with open("/dev/null", "w") as fd: config = {"exempt_exec_domain": "unconfined", "exempt_write_domain": "domain1 domain2 unconfined"} check = ReadOnlyExecutables(self.p, "test_pass", config) check.output = fd result = check.run() self.assertFalse(result) def test_pass2(self): """Test for passing with alternate exemptions.""" with open("/dev/null", "w") as fd: config = {"exempt_exec_domain": "unconfined", "exempt_file": "execfile2", "exempt_write_domain": "domain1 unconfined"} check = ReadOnlyExecutables(self.p, "test_pass2", config) check.output = fd result = check.run() self.assertFalse(result) setools-4.4.0/tests/checker/util.py000066400000000000000000000026421402045477700173220ustar00rootroot00000000000000# Copyright 2020, Microsoft Corporation # # This file is part of SETools. # # SETools 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. # # SETools 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 SETools. If not, see # . # import os import logging import unittest from setools.checker import util class CheckerUtilTest(unittest.TestCase): def test_config_bool_value(self): """Test config_bool_value""" self.assertTrue(util.config_bool_value(" TrUe ")) self.assertTrue((util.config_bool_value(" 1 "))) self.assertTrue((util.config_bool_value(" YeS "))) self.assertFalse((util.config_bool_value(" FalsE "))) self.assertFalse((util.config_bool_value(" 0 "))) self.assertFalse((util.config_bool_value(" No "))) self.assertTrue(util.config_bool_value(True)) self.assertFalse((util.config_bool_value(None))) self.assertFalse((util.config_bool_value(False))) setools-4.4.0/tests/commonquery.conf000066400000000000000000000033731402045477700176160ustar00rootroot00000000000000class infoflow class null class rw sid kernel sid security common test1 { hi_w hi_r super_r super_w } common test2a { send recv } common test2b { sig } common test10a { null } common test10b { null ping } common test11a { read write } common test11b { read } common test11c { write } common test12a { signal sigchld } common test12b { sigkill } class infoflow inherits test1 class null inherits test10a class rw inherits test11a sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; allow system system:infoflow hi_r; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/commonquery.py000066400000000000000000000052161402045477700173170ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import CommonQuery from .policyrep.util import compile_policy class CommonQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/commonquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Common query with no criteria.""" # query with no parameters gets all types. commons = sorted(self.p.commons()) q = CommonQuery(self.p) q_commons = sorted(q.results()) self.assertListEqual(commons, q_commons) def test_001_name_exact(self): """Common query with exact name match.""" q = CommonQuery(self.p, name="test1") commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], commons) def test_002_name_regex(self): """Common query with regex name match.""" q = CommonQuery(self.p, name="test2(a|b)", name_regex=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], commons) def test_010_perm_indirect_intersect(self): """Common query with intersect permission name patch.""" q = CommonQuery(self.p, perms=set(["null"]), perms_equal=False) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test10a", "test10b"], commons) def test_011_perm_indirect_equal(self): """Common query with equal permission name patch.""" q = CommonQuery(self.p, perms=set(["read", "write"]), perms_equal=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test11a"], commons) def test_012_perm_indirect_regex(self): """Common query with regex permission name patch.""" q = CommonQuery(self.p, perms="sig.+", perms_regex=True) commons = sorted(str(c) for c in q.results()) self.assertListEqual(["test12a", "test12b"], commons) setools-4.4.0/tests/conditionalinfoflow.conf000066400000000000000000000015321402045477700213020ustar00rootroot00000000000000class infoflow sid kernel class infoflow { hi_w hi_r med_r med_w } type system; role system; role system types system; ################################################# type src; type tgt; type flow_true; type flow_false; type src_remain; type tgt_remain; type flow_remain; bool condition false; allow src_remain flow_remain:infoflow hi_w; allow tgt_remain flow_remain:infoflow hi_r; if (condition) { allow src flow_true:infoflow hi_w; allow tgt flow_true:infoflow hi_r; allow tgt flow_true:infoflow hi_r; allow src_remain flow_remain:infoflow med_w; allow tgt_remain flow_remain:infoflow med_r; } else { allow src flow_false:infoflow hi_w; allow tgt flow_false:infoflow hi_r; } ################################################# #users user system roles system; #isids sid kernel system:system:system setools-4.4.0/tests/conditionalinfoflow.py000066400000000000000000000124671402045477700210160ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import InfoFlowAnalysis from setools import TERuletype as TERT from setools.exception import InvalidType from setools.permmap import PermissionMap from setools.policyrep import Type from . import mixins from .policyrep.util import compile_policy # Note: the testing for having correct rules on every edge is only # performed once on the full graph, since it is assumed that NetworkX's # Digraph.subgraph() function correctly copies the edge attributes into # the subgraph. class ConditionalInfoFlowAnalysisTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/conditionalinfoflow.conf", mls=False) cls.m = PermissionMap("tests/perm_map") cls.a = InfoFlowAnalysis(cls.p, cls.m) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_001_keep_conditional_rules(self): """Keep all conditional rules.""" self.a.booleans = None self.a._rebuildgraph = True self.a._build_subgraph() source = self.p.lookup_type("src") target = self.p.lookup_type("tgt") flow_true = self.p.lookup_type("flow_true") flow_false = self.p.lookup_type("flow_false") r = self.a.G.edges[source, flow_true]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[flow_true, target]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[source, flow_false]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[flow_false, target]["rules"] self.assertEqual(len(r), 1) def test_002_default_conditional_rules(self): """Keep only default conditional rules.""" self.a.booleans = {} self.a._rebuildgraph = True self.a._build_subgraph() source = self.p.lookup_type("src") target = self.p.lookup_type("tgt") flow_true = self.p.lookup_type("flow_true") flow_false = self.p.lookup_type("flow_false") r = self.a.G.edges[source, flow_true]["rules"] self.assertEqual(len(r), 0) r = self.a.G.edges[flow_true, target]["rules"] self.assertEqual(len(r), 0) r = self.a.G.edges[source, flow_false]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[flow_false, target]["rules"] self.assertEqual(len(r), 1) def test_003_user_conditional_true(self): """Keep only conditional rules selected by user specified booleans (True Case.)""" self.a.booleans = {"condition": True} self.a.rebuildgraph = True self.a._build_subgraph() source = self.p.lookup_type("src") target = self.p.lookup_type("tgt") flow_true = self.p.lookup_type("flow_true") flow_false = self.p.lookup_type("flow_false") r = self.a.G.edges[source, flow_true]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[flow_true, target]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[source, flow_false]["rules"] self.assertEqual(len(r), 0) r = self.a.G.edges[flow_false, target]["rules"] self.assertEqual(len(r), 0) def test_004_user_conditional_false(self): """Keep only conditional rules selected by user specified booleans (False Case.)""" self.a.booleans = {"condition": False} self.a.rebuildgraph = True self.a._build_subgraph() source = self.p.lookup_type("src") target = self.p.lookup_type("tgt") flow_true = self.p.lookup_type("flow_true") flow_false = self.p.lookup_type("flow_false") r = self.a.G.edges[source, flow_true]["rules"] self.assertEqual(len(r), 0) r = self.a.G.edges[flow_true, target]["rules"] self.assertEqual(len(r), 0) r = self.a.G.edges[source, flow_false]["rules"] self.assertEqual(len(r), 1) r = self.a.G.edges[flow_false, target]["rules"] self.assertEqual(len(r), 1) def test_005_remaining_edges(self): """Keep edges when rules are deleted, but there are still remaining rules on the edge.""" self.a.booleans = {} self.a.rebuildgraph = True self.a._build_subgraph() source = self.p.lookup_type("src_remain") target = self.p.lookup_type("tgt_remain") flow = self.p.lookup_type("flow_remain") r = self.a.G.edges[source, flow]["rules"] self.assertEqual(len(r), 1) self.assertEqual(str(r[0]), 'allow src_remain flow_remain:infoflow hi_w;') r = self.a.G.edges[flow, target]["rules"] self.assertEqual(len(r), 1) self.assertEqual(str(r[0]), 'allow tgt_remain flow_remain:infoflow hi_r;') setools-4.4.0/tests/constraintquery.conf000066400000000000000000000114751402045477700205140ustar00rootroot00000000000000class test1 class test10 class test11a class test11b class test11c class test12a class test12b class test12c class test20a class test20b class test20c class test21a class test21b class test21c class test30 class test31a class test31b class test40 class test41a class test41b class test50 class test51a class test51b sid kernel sid security common test { low_w med_w hi_w low_r med_r hi_r } class test1 inherits test class test10 inherits test class test11a inherits test class test11b inherits test class test11c inherits test class test12a inherits test class test12b inherits test class test12c inherits test class test20a { test20ap test20bp } class test20b { test20ap test20bp } class test20c { test20ap test20bp } class test21a { test21ap test21bp } class test21b { test21ap test21bp } class test21c { test21ap test21bp } class test30 inherits test class test31a inherits test class test31b inherits test class test40 inherits test class test41a inherits test class test41b inherits test class test50 inherits test class test51a inherits test class test51b inherits test sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; # test 1: # ruletype: mlsconstrain # tclass: unset # perms: unset mlsconstrain test1 hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role test30r; role test30r types system; role test31ra; role test31ra types system; role test31rb; role test31rb types system; type test40t; type test41ta; type test41tb; allow system system:test1 hi_r; user system roles system level med range low_s - high_s:here.lost; user test50u roles system level med range low_s - high_s:here.lost; user test51u1 roles system level med range low_s - high_s:here.lost; user test51u2 roles system level med range low_s - high_s:here.lost; # test 10: # ruletype: unset # tclass: test10 # perms: unset # role: unset # type: unset # user: unset constrain test10 hi_w (u1 == u2); # test 11: # ruletype: unset # tclass: test11a, test11b # perms: unset # role: unset # type: unset # user: unset constrain test11a hi_w (u1 == u2); constrain test11b hi_w (u1 == u2); constrain test11c hi_w (u1 == u2); # test 12: # ruletype: unset # tclass: intoflow12(a|c), regex # perms: unset # role: unset # type: unset # user: unset constrain test12a hi_w (u1 == u2); constrain test12b hi_w (u1 == u2); constrain test12c hi_w (u1 == u2); # test 20: # ruletype: unset # tclass: unset # perms: test20ap, test20bp # role: unset # type: unset # user: unset constrain test20a test20ap (u1 == u2); constrain test20b test20bp (u1 == u2); # test 21: # ruletype: unset # tclass: unset # perms: test21ap, test21bp, equal # role: unset # type: unset # user: unset constrain test21a test21ap (u1 == u2); constrain test21b test21bp (u1 == u2); constrain test21c { test21bp test21ap } (u1 == u2); # test 30: # ruletype: unset # tclass: unset # perms: unset # role: test30r # type: unset # user: unset constrain test30 hi_w (u1 == u2 or r1 == test30r); # test 31: # ruletype: unset # tclass: unset # perms: unset # role: test31r. regex # type: unset # user: unset constrain test31a hi_w (u1 == u2 or r1 == test31ra); validatetrans test31b (u1 == u2 or r2 == test31rb); # test 40: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: test40 # user: unset constrain test40 hi_w (u1 == u2 or t1 == test40t); # test 41: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: test41. regex # user: unset constrain test41a hi_w (u1 == u2 or t1 == test41ta); constrain test41b hi_w (u1 == u2 or t2 == test41tb); # test 50: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: unset # user: test50 constrain test50 hi_w (u1 == u2 or u1 == test50u); # test 51: # ruletype: unset # tclass: unset # perms: unset # role: unset # type: unset # user: test51u. regex constrain test51a hi_w (u1 == u2 or u1 == test51u1); constrain test51b hi_w (u1 == u2 or u2 == test51u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/constraintquery.py000066400000000000000000000112471402045477700202140ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import ConstraintQuery from .policyrep.util import compile_policy class ConstraintQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/constraintquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Constraint query with no criteria.""" allconstraint = sorted(c.tclass for c in self.p.constraints()) q = ConstraintQuery(self.p) qconstraint = sorted(c.tclass for c in q.results()) self.assertListEqual(allconstraint, qconstraint) def test_001_ruletype(self): """Constraint query with rule type match.""" q = ConstraintQuery(self.p, ruletype=["mlsconstrain"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test1"], constraint) @unittest.skip("Setting tclass to a string is no longer supported.") def test_010_class_exact(self): """Constraint query with exact object class match.""" q = ConstraintQuery(self.p, tclass="test10") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test10"], constraint) def test_011_class_list(self): """Constraint query with object class list match.""" q = ConstraintQuery(self.p, tclass=["test11a", "test11b"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test11a", "test11b"], constraint) def test_012_class_regex(self): """Constraint query with object class regex match.""" q = ConstraintQuery(self.p, tclass="test12(a|c)", tclass_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test12a", "test12c"], constraint) def test_020_perms_any(self): """Constraint query with permission set intersection match.""" q = ConstraintQuery(self.p, perms=["test20ap", "test20bp"]) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test20a", "test20b"], constraint) def test_021_perms_equal(self): """Constraint query with permission set equality match.""" q = ConstraintQuery(self.p, perms=["test21ap", "test21bp"], perms_equal=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test21c"], constraint) def test_030_role_match_single(self): """Constraint query with role match.""" q = ConstraintQuery(self.p, role="test30r") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test30"], constraint) def test_031_role_match_regex(self): """Constraint query with regex role match.""" q = ConstraintQuery(self.p, role="test31r.", role_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test31a", "test31b"], constraint) def test_040_type_match_single(self): """Constraint query with type match.""" q = ConstraintQuery(self.p, type_="test40t") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test40"], constraint) def test_041_type_match_regex(self): """Constraint query with regex type match.""" q = ConstraintQuery(self.p, type_="test41t.", type_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test41a", "test41b"], constraint) def test_050_user_match_single(self): """Constraint query with user match.""" q = ConstraintQuery(self.p, user="test50u") constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test50"], constraint) def test_051_user_match_regex(self): """Constraint query with regex user match.""" q = ConstraintQuery(self.p, user="test51u.", user_regex=True) constraint = sorted(c.tclass for c in q.results()) self.assertListEqual(["test51a", "test51b"], constraint) setools-4.4.0/tests/defaultquery.conf000066400000000000000000000044171402045477700177520ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } ######################################## # # Default settings # default_user infoflow target; default_role { infoflow infoflow3 } source; default_type infoflow4 target; default_range infoflow5 target low; default_range infoflow7 target high; default_range infoflow2 glblub; ######################################### sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/defaultquery.py000066400000000000000000000071461402045477700174570ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import DefaultQuery, DefaultRuletype, DefaultValue from setools.exception import InvalidClass from .policyrep.util import compile_policy class DefaultQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/defaultquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Default query: no criteria.""" # query with no parameters gets all defaults alldefaults = sorted(self.p.defaults()) q = DefaultQuery(self.p) qdefaults = sorted(q.results()) self.assertListEqual(alldefaults, qdefaults) def test_001_ruletype(self): """Default query: ruletype criterion.""" q = DefaultQuery(self.p, ruletype=["default_user"]) defaults = list(q.results()) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("infoflow", d.tclass) self.assertEqual(DefaultValue.target, d.default) def test_010_class_list(self): """Default query: object class list match.""" q = DefaultQuery(self.p, tclass=["infoflow3", "infoflow4"]) defaults = sorted(d.tclass for d in q.results()) self.assertListEqual(["infoflow3", "infoflow4"], defaults) def test_011_class_regex(self): """Default query: object class regex match.""" q = DefaultQuery(self.p, tclass="infoflow(3|5)", tclass_regex=True) defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow3", "infoflow5"], defaults) def test_020_default(self): """Default query: default setting.""" q = DefaultQuery(self.p, default="source") defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow", "infoflow3"], defaults) def test_030_default_range(self): """Default query: default_range setting.""" q = DefaultQuery(self.p, default_range="high") defaults = sorted(c.tclass for c in q.results()) self.assertListEqual(["infoflow7"], defaults) def test_900_invalid_ruletype(self): """Default query: invalid ruletype""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, ruletype=["INVALID"]) def test_901_invalid_class(self): """Default query: invalid object class""" with self.assertRaises(InvalidClass): q = DefaultQuery(self.p, tclass=["INVALID"]) def test_902_invalid_default_value(self): """Default query: invalid default value""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, default="INVALID") def test_903_invalid_default_range(self): """Default query: invalid default range""" with self.assertRaises(KeyError): q = DefaultQuery(self.p, default_range="INVALID") setools-4.4.0/tests/devicetreeconquery.conf000066400000000000000000000100451402045477700211370ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # irq: unset # user: unset # role: unset # type: unset # range: unset devicetreecon "/dev/tree1" system:system:system:s0:c0.c1 # test 10: # irq: unset # user: user10, exact # role: unset # type: unset # range: unset devicetreecon "/dev/tree10" user10:system:system:s0:c0.c1 # test 11: # irq: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset devicetreecon "/dev/tree11" user11a:system:system:s0:c0.c1 devicetreecon "/dev/tree11000" user11b:system:system:s0:c0.c1 devicetreecon "/dev/tree11001" user11c:system:system:s0:c0.c1 # test 20: # irq: unset # user: unset # role: role20_r, exact # type: unset # range: unset devicetreecon "/dev/tree20" system:role20_r:system:s0:c0.c1 # test 21: # irq: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset devicetreecon "/dev/tree21" system:role21a_r:system:s0:c0.c1 devicetreecon "/dev/tree21000" system:role21b_r:system:s0:c0.c1 devicetreecon "/dev/tree21001" system:role21c_r:system:s0:c0.c1 # test 30: # irq: unset # user: unset # role: unset # type: type30 # range: unset devicetreecon "/dev/tree30" system:system:type30:s0:c0.c1 # test 31: # irq: unset # user: unset # role: unset # type: type31(b|c) # range: unset devicetreecon "/dev/tree31" system:system:type31a:s0:c0.c1 devicetreecon "/dev/tree31000" system:system:type31b:s0:c0.c1 devicetreecon "/dev/tree31001" system:system:type31c:s0:c0.c1 # test 40: # irq: unset # user: unset # role: unset # type: unset # range: equal devicetreecon "/dev/tree40" system:system:system:s0:c1 - s0:c0.c4 # test 41: # irq: unset # user: unset # role: unset # type: unset # range: overlap devicetreecon "/dev/tree41" system:system:system:s1:c1 - s1:c1.c3 # test 42: # irq: unset # user: unset # role: unset # type: unset # range: subset devicetreecon "/dev/tree42" system:system:system:s2:c1 - s2:c1.c3 # test 43: # irq: unset # user: unset # role: unset # type: unset # range: superset devicetreecon "/dev/tree43" system:system:system:s3:c1 - s3:c1.c3 # test 44: # irq: unset # user: unset # role: unset # type: unset # range: proper subset devicetreecon "/dev/tree44" system:system:system:s4:c1 - s4:c1.c3 # test 45: # irq: unset # user: unset # role: unset # type: unset # range: proper superset devicetreecon "/dev/tree45" system:system:system:s5:c1 - s5:c1.c3 setools-4.4.0/tests/devicetreeconquery.py000066400000000000000000000215521402045477700206470ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import DevicetreeconQuery from .policyrep.util import compile_policy class DevicetreeconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/devicetreeconquery.conf", xen=True) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Devicetreecon query with no criteria""" # query with no parameters gets all PCI paths. rules = sorted(self.p.devicetreecons()) q = DevicetreeconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Devicetreecon query with context user exact match""" q = DevicetreeconQuery(self.p, user="user10", user_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree10")], path) def test_011_user_regex(self): """Devicetreecon query with context user regex match""" q = DevicetreeconQuery(self.p, user="user11(a|b)", user_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree11"), ("/dev/tree11000")], path) def test_020_role_exact(self): """Devicetreecon query with context role exact match""" q = DevicetreeconQuery(self.p, role="role20_r", role_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree20")], path) def test_021_role_regex(self): """Devicetreecon query with context role regex match""" q = DevicetreeconQuery(self.p, role="role21(a|c)_r", role_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree21"), ("/dev/tree21001")], path) def test_030_type_exact(self): """Devicetreecon query with context type exact match""" q = DevicetreeconQuery(self.p, type_="type30", type_regex=False) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree30")], path) def test_031_type_regex(self): """Devicetreecon query with context type regex match""" q = DevicetreeconQuery(self.p, type_="type31(b|c)", type_regex=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree31000"), ("/dev/tree31001")], path) def test_040_range_exact(self): """Devicetreecon query with context range exact match""" q = DevicetreeconQuery(self.p, range_="s0:c1 - s0:c0.c4") path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree40")], path) def test_041_range_overlap1(self): """Devicetreecon query with context range overlap match (equal)""" q = DevicetreeconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap2(self): """Devicetreecon query with context range overlap match (subset)""" q = DevicetreeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap3(self): """Devicetreecon query with context range overlap match (superset)""" q = DevicetreeconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap4(self): """Devicetreecon query with context range overlap match (overlap low level)""" q = DevicetreeconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_041_range_overlap5(self): """Devicetreecon query with context range overlap match (overlap high level)""" q = DevicetreeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree41")], path) def test_042_range_subset1(self): """Devicetreecon query with context range subset match""" q = DevicetreeconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree42")], path) def test_042_range_subset2(self): """Devicetreecon query with context range subset match (equal)""" q = DevicetreeconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree42")], path) def test_043_range_superset1(self): """Devicetreecon query with context range superset match""" q = DevicetreeconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree43")], path) def test_043_range_superset2(self): """Devicetreecon query with context range superset match (equal)""" q = DevicetreeconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree43")], path) def test_044_range_proper_subset1(self): """Devicetreecon query with context range proper subset match""" q = DevicetreeconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_044_range_proper_subset2(self): """Devicetreecon query with context range proper subset match (equal)""" q = DevicetreeconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([], path) def test_044_range_proper_subset3(self): """Devicetreecon query with context range proper subset match (equal low only)""" q = DevicetreeconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_044_range_proper_subset4(self): """Devicetreecon query with context range proper subset match (equal high only)""" q = DevicetreeconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree44")], path) def test_045_range_proper_superset1(self): """Devicetreecon query with context range proper superset match""" q = DevicetreeconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) def test_045_range_proper_superset2(self): """Devicetreecon query with context range proper superset match (equal)""" q = DevicetreeconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([], path) def test_045_range_proper_superset3(self): """Devicetreecon query with context range proper superset match (equal low)""" q = DevicetreeconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) def test_045_range_proper_superset4(self): """Devicetreecon query with context range proper superset match (equal high)""" q = DevicetreeconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) path = sorted(p.path for p in q.results()) self.assertListEqual([("/dev/tree45")], path) setools-4.4.0/tests/diff.py000066400000000000000000003554421402045477700156620ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # Copyright 2016, 2017, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from ipaddress import IPv6Address, IPv4Network, IPv6Network from setools import SELinuxPolicy, PolicyDifference, PortconProtocol from setools import BoundsRuletype as BRT from setools import ConstraintRuletype as CRT from setools import DefaultRuletype as DRT from setools import DefaultRangeValue as DRV from setools import DefaultValue as DV from setools import FSUseRuletype as FSURT from setools import MLSRuletype as MRT from setools import RBACRuletype as RRT from setools import TERuletype as TRT from .mixins import ValidateRule from .policyrep.util import compile_policy class PolicyDifferenceTest(ValidateRule, unittest.TestCase): """Policy difference tests.""" @classmethod def setUpClass(cls): cls.p_left = compile_policy("tests/diff_left.conf") cls.p_right = compile_policy("tests/diff_right.conf") cls.diff = PolicyDifference(cls.p_left, cls.p_right) @classmethod def tearDownClass(cls): os.unlink(cls.p_left.path) os.unlink(cls.p_right.path) # # Types # def test_added_types(self): """Diff: added type""" self.assertSetEqual(set(["added_type"]), self.diff.added_types) def test_removed_types(self): """Diff: modified type""" self.assertSetEqual(set(["removed_type"]), self.diff.removed_types) def test_modified_types_count(self): """Diff: total modified types""" self.assertEqual(6, len(self.diff.modified_types)) def test_modified_types_remove_attr(self): """Diff: modified type with removed attribute.""" self.assertIn("modified_remove_attr", self.diff.modified_types) removed_attrs = self.diff.modified_types["modified_remove_attr"].removed_attributes self.assertSetEqual(set(["an_attr"]), removed_attrs) self.assertFalse(self.diff.modified_types["modified_remove_attr"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_attr"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_remove_attr"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_remove_attr"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_attr"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_attr"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_remove_attr"].matched_aliases) def test_modified_types_remove_alias(self): """Diff: modified type with removed alias.""" self.assertIn("modified_remove_alias", self.diff.modified_types) removed_alias = self.diff.modified_types["modified_remove_alias"].removed_aliases self.assertSetEqual(set(["an_alias"]), removed_alias) self.assertFalse(self.diff.modified_types["modified_remove_alias"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_remove_alias"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_remove_alias"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_alias"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_alias"].matched_aliases) def test_modified_types_remove_permissive(self): """Diff: modified type with removed permissve.""" self.assertIn("modified_remove_permissive", self.diff.modified_types) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].added_attributes) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].matched_attributes) self.assertTrue(self.diff.modified_types["modified_remove_permissive"].modified_permissive) self.assertTrue(self.diff.modified_types["modified_remove_permissive"].permissive) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].added_aliases) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_remove_permissive"].matched_aliases) def test_modified_types_add_attr(self): """Diff: modified type with added attribute.""" self.assertIn("modified_add_attr", self.diff.modified_types) added_attrs = self.diff.modified_types["modified_add_attr"].added_attributes self.assertSetEqual(set(["an_attr"]), added_attrs) self.assertFalse(self.diff.modified_types["modified_add_attr"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_attr"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_add_attr"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_attr"].permissive) self.assertFalse(self.diff.modified_types["modified_add_attr"].added_aliases) self.assertFalse(self.diff.modified_types["modified_add_attr"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_attr"].matched_aliases) def test_modified_types_add_alias(self): """Diff: modified type with added alias.""" self.assertIn("modified_add_alias", self.diff.modified_types) added_alias = self.diff.modified_types["modified_add_alias"].added_aliases self.assertSetEqual(set(["an_alias"]), added_alias) self.assertFalse(self.diff.modified_types["modified_add_alias"].added_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].matched_attributes) self.assertFalse(self.diff.modified_types["modified_add_alias"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_alias"].permissive) self.assertFalse(self.diff.modified_types["modified_add_alias"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_alias"].matched_aliases) def test_modified_types_add_permissive(self): """Diff: modified type with added permissive.""" self.assertIn("modified_add_permissive", self.diff.modified_types) self.assertFalse(self.diff.modified_types["modified_add_permissive"].added_attributes) self.assertFalse(self.diff.modified_types["modified_add_permissive"].removed_attributes) self.assertFalse(self.diff.modified_types["modified_add_permissive"].matched_attributes) self.assertTrue(self.diff.modified_types["modified_add_permissive"].modified_permissive) self.assertFalse(self.diff.modified_types["modified_add_permissive"].permissive) self.assertFalse(self.diff.modified_types["modified_add_permissive"].added_aliases) self.assertFalse(self.diff.modified_types["modified_add_permissive"].removed_aliases) self.assertFalse(self.diff.modified_types["modified_add_permissive"].matched_aliases) # # Roles # def test_added_role(self): """Diff: added role.""" self.assertSetEqual(set(["added_role"]), self.diff.added_roles) def test_removed_role(self): """Diff: removed role.""" self.assertSetEqual(set(["removed_role"]), self.diff.removed_roles) def test_modified_role_count(self): """Diff: modified role.""" self.assertEqual(2, len(self.diff.modified_roles)) def test_modified_role_add_type(self): """Diff: modified role with added type.""" self.assertSetEqual(set(["system"]), self.diff.modified_roles["modified_add_type"].added_types) self.assertFalse(self.diff.modified_roles["modified_add_type"].removed_types) def test_modified_role_remove_type(self): """Diff: modified role with removed type.""" self.assertSetEqual(set(["system"]), self.diff.modified_roles["modified_remove_type"].removed_types) self.assertFalse(self.diff.modified_roles["modified_remove_type"].added_types) # # Commons # def test_added_common(self): """Diff: added common.""" self.assertSetEqual(set(["added_common"]), self.diff.added_commons) def test_removed_common(self): """Diff: removed common.""" self.assertSetEqual(set(["removed_common"]), self.diff.removed_commons) def test_modified_common_count(self): """Diff: modified common count.""" self.assertEqual(2, len(self.diff.modified_commons)) def test_modified_common_add_perm(self): """Diff: modified common with added perm.""" self.assertSetEqual(set(["added_perm"]), self.diff.modified_commons["modified_add_perm"].added_perms) self.assertFalse(self.diff.modified_commons["modified_add_perm"].removed_perms) def test_modified_common_remove_perm(self): """Diff: modified common with removed perm.""" self.assertSetEqual(set(["removed_perm"]), self.diff.modified_commons["modified_remove_perm"].removed_perms) self.assertFalse(self.diff.modified_commons["modified_remove_perm"].added_perms) # # Classes # def test_added_class(self): """Diff: added class.""" self.assertSetEqual(set(["added_class"]), self.diff.added_classes) def test_removed_class(self): """Diff: removed class.""" self.assertSetEqual(set(["removed_class"]), self.diff.removed_classes) def test_modified_class_count(self): """Diff: modified class count.""" self.assertEqual(3, len(self.diff.modified_classes)) def test_modified_class_add_perm(self): """Diff: modified class with added perm.""" self.assertSetEqual(set(["added_perm"]), self.diff.modified_classes["modified_add_perm"].added_perms) self.assertFalse(self.diff.modified_classes["modified_add_perm"].removed_perms) def test_modified_class_remove_perm(self): """Diff: modified class with removed perm.""" self.assertSetEqual(set(["removed_perm"]), self.diff.modified_classes["modified_remove_perm"].removed_perms) self.assertFalse(self.diff.modified_classes["modified_remove_perm"].added_perms) def test_modified_class_change_common(self): """Diff: modified class due to modified common.""" self.assertSetEqual(set(["old_com"]), self.diff.modified_classes["modified_change_common"].removed_perms) self.assertSetEqual(set(["new_com"]), self.diff.modified_classes["modified_change_common"].added_perms) # # Allow rules # def test_added_allow_rules(self): """Diff: added allow rules.""" rules = sorted(self.diff.added_allows) self.assertEqual(5, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.allow, "added_rule_source", "added_rule_target", "infoflow", set(["med_w"])) # added rule with new type self.validate_rule(rules[1], TRT.allow, "added_type", "added_type", "infoflow2", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[2], TRT.allow, "move_from_bool", "move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[3], TRT.allow, "move_to_bool", "move_to_bool", "infoflow4", set(["hi_w"]), cond="move_to_bool_b", cond_block=True) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.allow, "system", "switch_block", "infoflow6", set(["hi_r"]), cond="switch_block_b", cond_block=False) def test_removed_allow_rules(self): """Diff: removed allow rules.""" rules = sorted(self.diff.removed_allows) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.allow, "move_from_bool", "move_from_bool", "infoflow4", set(["hi_r"]), cond="move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.allow, "move_to_bool", "move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.allow, "removed_rule_source", "removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.allow, "removed_type", "removed_type", "infoflow3", set(["null"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.allow, "system", "switch_block", "infoflow6", set(["hi_r"]), cond="switch_block_b", cond_block=True) def test_modified_allow_rules(self): """Diff: modified allow rules.""" lst = sorted(self.diff.modified_allows, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_add_perms", rule.source) self.assertEqual("modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_add_remove_perms", rule.source) self.assertEqual("modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.allow, rule.ruletype) self.assertEqual("modified_rule_remove_perms", rule.source) self.assertEqual("modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Auditallow rules # def test_added_auditallow_rules(self): """Diff: added auditallow rules.""" rules = sorted(self.diff.added_auditallows) self.assertEqual(5, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.auditallow, "aa_added_rule_source", "aa_added_rule_target", "infoflow", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[1], TRT.auditallow, "aa_move_from_bool", "aa_move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[2], TRT.auditallow, "aa_move_to_bool", "aa_move_to_bool", "infoflow4", set(["hi_w"]), cond="aa_move_to_bool_b", cond_block=True) # added rule with new type self.validate_rule(rules[3], TRT.auditallow, "added_type", "added_type", "infoflow7", set(["super_none"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.auditallow, "system", "aa_switch_block", "infoflow6", set(["hi_r"]), cond="aa_switch_block_b", cond_block=False) def test_removed_auditallow_rules(self): """Diff: removed auditallow rules.""" rules = sorted(self.diff.removed_auditallows) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.auditallow, "aa_move_from_bool", "aa_move_from_bool", "infoflow4", set(["hi_r"]), cond="aa_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.auditallow, "aa_move_to_bool", "aa_move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.auditallow, "aa_removed_rule_source", "aa_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.auditallow, "removed_type", "removed_type", "infoflow7", set(["super_unmapped"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.auditallow, "system", "aa_switch_block", "infoflow6", set(["hi_r"]), cond="aa_switch_block_b", cond_block=True) def test_modified_auditallow_rules(self): """Diff: modified auditallow rules.""" lst = sorted(self.diff.modified_auditallows, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_add_perms", rule.source) self.assertEqual("aa_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_add_remove_perms", rule.source) self.assertEqual("aa_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.auditallow, rule.ruletype) self.assertEqual("aa_modified_rule_remove_perms", rule.source) self.assertEqual("aa_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Dontaudit rules # def test_added_dontaudit_rules(self): """Diff: added dontaudit rules.""" rules = sorted(self.diff.added_dontaudits) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.dontaudit, "added_type", "added_type", "infoflow7", set(["super_none"])) # added rule with existing types self.validate_rule(rules[1], TRT.dontaudit, "da_added_rule_source", "da_added_rule_target", "infoflow", set(["med_w"])) # rule moved out of a conditional self.validate_rule(rules[2], TRT.dontaudit, "da_move_from_bool", "da_move_from_bool", "infoflow4", set(["hi_r"])) # rule moved into a conditional self.validate_rule(rules[3], TRT.dontaudit, "da_move_to_bool", "da_move_to_bool", "infoflow4", set(["hi_w"]), cond="da_move_to_bool_b", cond_block=True) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.dontaudit, "system", "da_switch_block", "infoflow6", set(["hi_r"]), cond="da_switch_block_b", cond_block=False) def test_removed_dontaudit_rules(self): """Diff: removed dontaudit rules.""" rules = sorted(self.diff.removed_dontaudits) self.assertEqual(5, len(rules)) # rule moved out of a conditional self.validate_rule(rules[0], TRT.dontaudit, "da_move_from_bool", "da_move_from_bool", "infoflow4", set(["hi_r"]), cond="da_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[1], TRT.dontaudit, "da_move_to_bool", "da_move_to_bool", "infoflow4", set(["hi_w"])) # removed rule with existing types self.validate_rule(rules[2], TRT.dontaudit, "da_removed_rule_source", "da_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type self.validate_rule(rules[3], TRT.dontaudit, "removed_type", "removed_type", "infoflow7", set(["super_both"])) # rule moved from one conditional block to another (true to false) self.validate_rule(rules[4], TRT.dontaudit, "system", "da_switch_block", "infoflow6", set(["hi_r"]), cond="da_switch_block_b", cond_block=True) def test_modified_dontaudit_rules(self): """Diff: modified dontaudit rules.""" lst = sorted(self.diff.modified_dontaudits, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_add_perms", rule.source) self.assertEqual("da_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set(["hi_w"]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set(["hi_r"]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_add_remove_perms", rule.source) self.assertEqual("da_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set(["super_r"]), added_perms) self.assertSetEqual(set(["super_w"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.dontaudit, rule.ruletype) self.assertEqual("da_modified_rule_remove_perms", rule.source) self.assertEqual("da_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set(["low_r"]), removed_perms) self.assertSetEqual(set(["low_w"]), matched_perms) # # Neverallow rules # def test_added_neverallow_rules(self): """Diff: added neverallow rules.""" self.assertFalse(self.diff.added_neverallows) # changed after dropping source policy support # rules = sorted(self.diff.added_neverallows) # self.assertEqual(2, len(rules)) # added rule with new type # self.validate_rule(rules[0], TRT.neverallow, "added_type", "added_type", "added_class", # set(["new_class_perm"])) # added rule with existing types # self.validate_rule(rules[1], TRT.neverallow, "na_added_rule_source", # "na_added_rule_target", "infoflow", set(["med_w"])) def test_removed_neverallow_rules(self): """Diff: removed neverallow rules.""" self.assertFalse(self.diff.removed_neverallows) # changed after dropping source policy support # rules = sorted(self.diff.removed_neverallows) # self.assertEqual(2, len(rules)) # removed rule with existing types # self.validate_rule(rules[0], TRT.neverallow, "na_removed_rule_source", # "na_removed_rule_target", "infoflow", set(["hi_r"])) # removed rule with new type # self.validate_rule(rules[1], TRT.neverallow, "removed_type", "removed_type", # "removed_class", set(["null_perm"])) def test_modified_neverallow_rules(self): """Diff: modified neverallow rules.""" # changed after dropping source policy support self.assertFalse(self.diff.modified_neverallows) # l = sorted(self.diff.modified_neverallows, key=lambda x: x.rule) # self.assertEqual(3, len(l)) # # # add permissions # rule, added_perms, removed_perms, matched_perms = l[0] # self.assertEqual(TRT.neverallow, rule.ruletype) # self.assertEqual("na_modified_rule_add_perms", rule.source) # self.assertEqual("na_modified_rule_add_perms", rule.target) # self.assertEqual("infoflow", rule.tclass) # self.assertSetEqual(set(["hi_w"]), added_perms) # self.assertFalse(removed_perms) # self.assertSetEqual(set(["hi_r"]), matched_perms) # # # add and remove permissions # rule, added_perms, removed_perms, matched_perms = l[1] # self.assertEqual(TRT.neverallow, rule.ruletype) # self.assertEqual("na_modified_rule_add_remove_perms", rule.source) # self.assertEqual("na_modified_rule_add_remove_perms", rule.target) # self.assertEqual("infoflow2", rule.tclass) # self.assertSetEqual(set(["super_r"]), added_perms) # self.assertSetEqual(set(["super_w"]), removed_perms) # self.assertSetEqual(set(["low_w"]), matched_perms) # # # remove permissions # rule, added_perms, removed_perms, matched_perms = l[2] # self.assertEqual(TRT.neverallow, rule.ruletype) # self.assertEqual("na_modified_rule_remove_perms", rule.source) # self.assertEqual("na_modified_rule_remove_perms", rule.target) # self.assertEqual("infoflow", rule.tclass) # self.assertFalse(added_perms) # self.assertSetEqual(set(["low_r"]), removed_perms) # self.assertSetEqual(set(["low_w"]), matched_perms) # # Type_transition rules # def test_added_type_transition_rules(self): """Diff: added type_transition rules.""" rules = sorted(self.diff.added_type_transitions) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_transition, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_transition, "system", "tt_switch_block", "infoflow6", "system", cond="tt_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_transition, "tt_added_rule_source", "tt_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_transition, "tt_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_transition, "tt_move_to_bool", "system", "infoflow3", "system", cond="tt_move_to_bool_b", cond_block=True) def test_removed_type_transition_rules(self): """Diff: removed type_transition rules.""" rules = sorted(self.diff.removed_type_transitions) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_transition, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_transition, "system", "tt_switch_block", "infoflow6", "system", cond="tt_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_transition, "tt_move_from_bool", "system", "infoflow4", "system", cond="tt_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_transition, "tt_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_transition, "tt_removed_rule_source", "tt_removed_rule_target", "infoflow", "system") def test_modified_type_transition_rules(self): """Diff: modified type_transition rules.""" lst = sorted(self.diff.modified_type_transitions, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_default, removed_default = lst[0] self.assertEqual(TRT.type_transition, rule.ruletype) self.assertEqual("tt_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tt_new_type", added_default) self.assertEqual("tt_old_type", removed_default) # # Type_change rules # def test_added_type_change_rules(self): """Diff: added type_change rules.""" rules = sorted(self.diff.added_type_changes) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_change, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_change, "system", "tc_switch_block", "infoflow6", "system", cond="tc_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_change, "tc_added_rule_source", "tc_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_change, "tc_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_change, "tc_move_to_bool", "system", "infoflow3", "system", cond="tc_move_to_bool_b", cond_block=True) def test_removed_type_change_rules(self): """Diff: removed type_change rules.""" rules = sorted(self.diff.removed_type_changes) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_change, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_change, "system", "tc_switch_block", "infoflow6", "system", cond="tc_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_change, "tc_move_from_bool", "system", "infoflow4", "system", cond="tc_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_change, "tc_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_change, "tc_removed_rule_source", "tc_removed_rule_target", "infoflow", "system") def test_modified_type_change_rules(self): """Diff: modified type_change rules.""" lst = sorted(self.diff.modified_type_changes, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_default, removed_default = lst[0] self.assertEqual(TRT.type_change, rule.ruletype) self.assertEqual("tc_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tc_new_type", added_default) self.assertEqual("tc_old_type", removed_default) # # Type_member rules # def test_added_type_member_rules(self): """Diff: added type_member rules.""" rules = sorted(self.diff.added_type_members) self.assertEqual(5, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.type_member, "added_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_member, "system", "tm_switch_block", "infoflow6", "system", cond="tm_switch_block_b", cond_block=False) # added rule with existing types self.validate_rule(rules[2], TRT.type_member, "tm_added_rule_source", "tm_added_rule_target", "infoflow", "system") # rule moved out of a conditional self.validate_rule(rules[3], TRT.type_member, "tm_move_from_bool", "system", "infoflow4", "system") # rule moved into a conditional self.validate_rule(rules[4], TRT.type_member, "tm_move_to_bool", "system", "infoflow3", "system", cond="tm_move_to_bool_b", cond_block=True) def test_removed_type_member_rules(self): """Diff: removed type_member rules.""" rules = sorted(self.diff.removed_type_members) self.assertEqual(5, len(rules)) # removed rule with new type self.validate_rule(rules[0], TRT.type_member, "removed_type", "system", "infoflow4", "system") # rule moved from one conditional block to another (true to false) self.validate_rule(rules[1], TRT.type_member, "system", "tm_switch_block", "infoflow6", "system", cond="tm_switch_block_b", cond_block=True) # rule moved out of a conditional self.validate_rule(rules[2], TRT.type_member, "tm_move_from_bool", "system", "infoflow4", "system", cond="tm_move_from_bool_b", cond_block=True) # rule moved into a conditional self.validate_rule(rules[3], TRT.type_member, "tm_move_to_bool", "system", "infoflow3", "system") # removed rule with existing types self.validate_rule(rules[4], TRT.type_member, "tm_removed_rule_source", "tm_removed_rule_target", "infoflow", "system") def test_modified_type_member_rules(self): """Diff: modified type_member rules.""" lst = sorted(self.diff.modified_type_members, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_default, removed_default = lst[0] self.assertEqual(TRT.type_member, rule.ruletype) self.assertEqual("tm_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("tm_new_type", added_default) self.assertEqual("tm_old_type", removed_default) # # Range_transition rules # def test_added_range_transition_rules(self): """Diff: added range_transition rules.""" rules = sorted(self.diff.added_range_transitions) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], MRT.range_transition, "added_type", "system", "infoflow4", "s3") # added rule with existing types self.validate_rule(rules[1], MRT.range_transition, "rt_added_rule_source", "rt_added_rule_target", "infoflow", "s3") def test_removed_range_transition_rules(self): """Diff: removed range_transition rules.""" rules = sorted(self.diff.removed_range_transitions) self.assertEqual(2, len(rules)) # removed rule with new type self.validate_rule(rules[0], MRT.range_transition, "removed_type", "system", "infoflow4", "s1") # removed rule with existing types self.validate_rule(rules[1], MRT.range_transition, "rt_removed_rule_source", "rt_removed_rule_target", "infoflow", "s1") def test_modified_range_transition_rules(self): """Diff: modified range_transition rules.""" lst = sorted(self.diff.modified_range_transitions, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_default, removed_default = lst[0] self.assertEqual(MRT.range_transition, rule.ruletype) self.assertEqual("rt_matched_source", rule.source) self.assertEqual("system", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertEqual("s0:c0,c4 - s1:c0.c2,c4", added_default) self.assertEqual("s2:c0 - s3:c0.c2", removed_default) # # Role allow rules # def test_added_role_allow_rules(self): """Diff: added role_allow rules.""" rules = sorted(self.diff.added_role_allows) self.assertEqual(2, len(rules)) # added rule with existing roles self.assertEqual(RRT.allow, rules[0].ruletype) self.assertEqual("added_role", rules[0].source) self.assertEqual("system", rules[0].target) # added rule with new roles self.assertEqual(RRT.allow, rules[1].ruletype) self.assertEqual("added_rule_source_r", rules[1].source) self.assertEqual("added_rule_target_r", rules[1].target) def test_removed_role_allow_rules(self): """Diff: removed role_allow rules.""" rules = sorted(self.diff.removed_role_allows) self.assertEqual(2, len(rules)) # removed rule with removed role self.assertEqual(RRT.allow, rules[0].ruletype) self.assertEqual("removed_role", rules[0].source) self.assertEqual("system", rules[0].target) # removed rule with existing roles self.assertEqual(RRT.allow, rules[1].ruletype) self.assertEqual("removed_rule_source_r", rules[1].source) self.assertEqual("removed_rule_target_r", rules[1].target) # # Role_transition rules # def test_added_role_transition_rules(self): """Diff: added role_transition rules.""" rules = sorted(self.diff.added_role_transitions) self.assertEqual(2, len(rules)) # added rule with new role self.validate_rule(rules[0], RRT.role_transition, "added_role", "system", "infoflow4", "system") # added rule with existing roles self.validate_rule(rules[1], RRT.role_transition, "role_tr_added_rule_source", "role_tr_added_rule_target", "infoflow6", "system") def test_removed_role_transition_rules(self): """Diff: removed role_transition rules.""" rules = sorted(self.diff.removed_role_transitions) self.assertEqual(2, len(rules)) # removed rule with new role self.validate_rule(rules[0], RRT.role_transition, "removed_role", "system", "infoflow4", "system") # removed rule with existing roles self.validate_rule(rules[1], RRT.role_transition, "role_tr_removed_rule_source", "role_tr_removed_rule_target", "infoflow5", "system") def test_modified_role_transition_rules(self): """Diff: modified role_transition rules.""" lst = sorted(self.diff.modified_role_transitions, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_default, removed_default = lst[0] self.assertEqual(RRT.role_transition, rule.ruletype) self.assertEqual("role_tr_matched_source", rule.source) self.assertEqual("role_tr_matched_target", rule.target) self.assertEqual("infoflow3", rule.tclass) self.assertEqual("role_tr_new_role", added_default) self.assertEqual("role_tr_old_role", removed_default) # # Users # def test_added_user(self): """Diff: added user.""" self.assertSetEqual(set(["added_user"]), self.diff.added_users) def test_removed_user(self): """Diff: removed user.""" self.assertSetEqual(set(["removed_user"]), self.diff.removed_users) def test_modified_user_count(self): """Diff: modified user count.""" self.assertEqual(4, len(self.diff.modified_users)) def test_modified_user_add_role(self): """Diff: modified user with added role.""" self.assertSetEqual(set(["added_role"]), self.diff.modified_users["modified_add_role"].added_roles) self.assertFalse(self.diff.modified_users["modified_add_role"].removed_roles) def test_modified_user_remove_role(self): """Diff: modified user with removed role.""" self.assertSetEqual(set(["removed_role"]), self.diff.modified_users["modified_remove_role"].removed_roles) self.assertFalse(self.diff.modified_users["modified_remove_role"].added_roles) def test_modified_user_change_level(self): """Diff: modified user due to modified default level.""" self.assertEqual("s2:c0", self.diff.modified_users["modified_change_level"].removed_level) self.assertEqual("s2:c1", self.diff.modified_users["modified_change_level"].added_level) def test_modified_user_change_range(self): """Diff: modified user due to modified range.""" self.assertEqual("s3:c1 - s3:c1.c3", self.diff.modified_users["modified_change_range"].removed_range) self.assertEqual("s3:c1 - s3:c1.c4", self.diff.modified_users["modified_change_range"].added_range) # # Type attributes # def test_added_type_attribute(self): """Diff: added type attribute.""" self.assertSetEqual(set(["added_attr"]), self.diff.added_type_attributes) def test_removed_type_attribute(self): """Diff: removed type attribute.""" self.assertSetEqual(set(["removed_attr"]), self.diff.removed_type_attributes) def test_modified_type_attribute(self): """Diff: modified type attribute.""" self.assertEqual(1, len(self.diff.modified_type_attributes)) self.assertSetEqual(set(["modified_add_attr"]), self.diff.modified_type_attributes["an_attr"].added_types) self.assertSetEqual(set(["modified_remove_attr"]), self.diff.modified_type_attributes["an_attr"].removed_types) # # Booleans # def test_added_boolean(self): """Diff: added boolean.""" self.assertSetEqual(set(["added_bool"]), self.diff.added_booleans) def test_removed_boolean(self): """Diff: removed boolean.""" self.assertSetEqual(set(["removed_bool"]), self.diff.removed_booleans) def test_modified_boolean(self): """Diff: modified boolean.""" self.assertEqual(1, len(self.diff.modified_booleans)) self.assertTrue(self.diff.modified_booleans["modified_bool"].added_state) self.assertFalse(self.diff.modified_booleans["modified_bool"].removed_state) # # Categories # def test_added_category(self): """Diff: added category.""" self.assertSetEqual(set(["c6"]), self.diff.added_categories) def test_removed_category(self): """Diff: removed category.""" self.assertSetEqual(set(["c5"]), self.diff.removed_categories) def test_modified_category(self): """Diff: modified categories.""" self.assertEqual(2, len(self.diff.modified_categories)) # add alias self.assertEqual(set(["foo"]), self.diff.modified_categories["c1"].added_aliases) self.assertFalse(self.diff.modified_categories["c1"].removed_aliases) # remove alias self.assertFalse(self.diff.modified_categories["c0"].added_aliases) self.assertEqual(set(["eggs"]), self.diff.modified_categories["c0"].removed_aliases) # # Sensitivity # def test_added_sensitivities(self): """Diff: added sensitivities.""" self.assertSetEqual(set(["s46"]), self.diff.added_sensitivities) def test_removed_sensitivities(self): """Diff: removed sensitivities.""" self.assertSetEqual(set(["s47"]), self.diff.removed_sensitivities) def test_modified_sensitivities(self): """Diff: modified sensitivities.""" self.assertEqual(2, len(self.diff.modified_sensitivities)) # add alias self.assertSetEqual(set(["al4"]), self.diff.modified_sensitivities["s1"].added_aliases) self.assertFalse(self.diff.modified_sensitivities["s1"].removed_aliases) # remove alias self.assertFalse(self.diff.modified_sensitivities["s0"].added_aliases) self.assertSetEqual(set(["al2"]), self.diff.modified_sensitivities["s0"].removed_aliases) # # Initial SIDs # def test_added_initialsids(self): """Diff: added initialsids.""" self.assertSetEqual(set(["file_labels"]), self.diff.added_initialsids) @unittest.skip("Moved to PolicyDifferenceRmIsidTest.") def test_removed_initialsids(self): """Diff: removed initialsids.""" self.assertSetEqual(set(["removed_sid"]), self.diff.removed_initialsids) def test_modified_initialsids(self): """Diff: modified initialsids.""" self.assertEqual(1, len(self.diff.modified_initialsids)) self.assertEqual("system:system:system:s0", self.diff.modified_initialsids["fs"].added_context) self.assertEqual("removed_user:system:system:s0", self.diff.modified_initialsids["fs"].removed_context) # # fs_use_* # def test_added_fs_uses(self): """Diff: added fs_uses.""" lst = sorted(self.diff.added_fs_uses) self.assertEqual(1, len(lst)) rule = lst[0] self.assertEqual(FSURT.fs_use_xattr, rule.ruletype) self.assertEqual("added_fsuse", rule.fs) self.assertEqual("system:object_r:system:s0", rule.context) def test_removed_fs_uses(self): """Diff: removed fs_uses.""" lst = sorted(self.diff.removed_fs_uses) self.assertEqual(1, len(lst)) rule = lst[0] self.assertEqual(FSURT.fs_use_task, rule.ruletype) self.assertEqual("removed_fsuse", rule.fs) self.assertEqual("system:object_r:system:s0", rule.context) def test_modified_fs_uses(self): """Diff: modified fs_uses.""" lst = sorted(self.diff.modified_fs_uses, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_context, removed_context = lst[0] self.assertEqual(FSURT.fs_use_trans, rule.ruletype) self.assertEqual("modified_fsuse", rule.fs) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # genfscon # def test_added_genfscons(self): """Diff: added genfscons.""" lst = sorted(self.diff.added_genfscons) self.assertEqual(2, len(lst)) rule = lst[0] self.assertEqual("added_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("added_user:object_r:system:s0", rule.context) rule = lst[1] self.assertEqual("change_path", rule.fs) self.assertEqual("/new", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) def test_removed_genfscons(self): """Diff: removed genfscons.""" lst = sorted(self.diff.removed_genfscons) self.assertEqual(2, len(lst)) rule = lst[0] self.assertEqual("change_path", rule.fs) self.assertEqual("/old", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) rule = lst[1] self.assertEqual("removed_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("system:object_r:system:s0", rule.context) def test_modified_genfscons(self): """Diff: modified genfscons.""" lst = sorted(self.diff.modified_genfscons, key=lambda x: x.rule) self.assertEqual(1, len(lst)) rule, added_context, removed_context = lst[0] self.assertEqual("modified_genfs", rule.fs) self.assertEqual("/", rule.path) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # level decl # def test_added_levels(self): """Diff: added levels.""" lst = sorted(self.diff.added_levels) self.assertEqual(1, len(lst)) self.assertEqual("s46:c0.c4", lst[0]) def test_removed_levels(self): """Diff: removed levels.""" lst = sorted(self.diff.removed_levels) self.assertEqual(1, len(lst)) self.assertEqual("s47:c0.c4", lst[0]) def test_modified_levels(self): """Diff: modified levels.""" lst = sorted(self.diff.modified_levels) self.assertEqual(2, len(lst)) level = lst[0] self.assertEqual("s40", level.level.sensitivity) self.assertSetEqual(set(["c3"]), level.added_categories) self.assertFalse(level.removed_categories) level = lst[1] self.assertEqual("s41", level.level.sensitivity) self.assertFalse(level.added_categories) self.assertSetEqual(set(["c4"]), level.removed_categories) # # netifcon # def test_added_netifcons(self): """Diff: added netifcons.""" lst = sorted(self.diff.added_netifcons) self.assertEqual(1, len(lst)) rule = lst[0] self.assertEqual("added_netif", rule.netif) self.assertEqual("system:object_r:system:s0", rule.context) self.assertEqual("system:object_r:system:s0", rule.packet) def test_removed_netifcons(self): """Diff: removed netifcons.""" lst = sorted(self.diff.removed_netifcons) self.assertEqual(1, len(lst)) rule = lst[0] self.assertEqual("removed_netif", rule.netif) self.assertEqual("system:object_r:system:s0", rule.context) self.assertEqual("system:object_r:system:s0", rule.packet) def test_modified_netifcons(self): """Diff: modified netifcons.""" lst = sorted(self.diff.modified_netifcons, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # modified both contexts rule, added_context, removed_context, added_packet, removed_packet = lst[0] self.assertEqual("mod_both_netif", rule.netif) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) self.assertEqual("added_user:object_r:system:s0", added_packet) self.assertEqual("removed_user:object_r:system:s0", removed_packet) # modified context rule, added_context, removed_context, added_packet, removed_packet = lst[1] self.assertEqual("mod_ctx_netif", rule.netif) self.assertEqual("added_user:object_r:system:s0", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) self.assertIsNone(added_packet) self.assertIsNone(removed_packet) # modified packet context rule, added_context, removed_context, added_packet, removed_packet = lst[2] self.assertEqual("mod_pkt_netif", rule.netif) self.assertIsNone(added_context) self.assertIsNone(removed_context) self.assertEqual("added_user:object_r:system:s0", added_packet) self.assertEqual("removed_user:object_r:system:s0", removed_packet) # # nodecons # def test_added_nodecons(self): """Diff: added nodecons.""" lst = sorted(self.diff.added_nodecons) self.assertEqual(4, len(lst)) # new IPv4 nodecon = lst[0] self.assertEqual(IPv4Network("124.0.0.0/8"), nodecon.network) # changed IPv4 netmask nodecon = lst[1] self.assertEqual(IPv4Network("125.0.0.0/16"), nodecon.network) # new IPv6 nodecon = lst[2] self.assertEqual(IPv6Network("ff04::/62"), nodecon.network) # changed IPv6 netmask nodecon = lst[3] self.assertEqual(IPv6Network("ff05::/60"), nodecon.network) def test_removed_nodecons(self): """Diff: removed nodecons.""" lst = sorted(self.diff.removed_nodecons) self.assertEqual(4, len(lst)) # new IPv4 nodecon = lst[0] self.assertEqual(IPv4Network("122.0.0.0/8"), nodecon.network) # changed IPv4 netmask nodecon = lst[1] self.assertEqual(IPv4Network("125.0.0.0/8"), nodecon.network) # new IPv6 nodecon = lst[2] self.assertEqual(IPv6Network("ff02::/62"), nodecon.network) # changed IPv6 netmask nodecon = lst[3] self.assertEqual(IPv6Network("ff05::/62"), nodecon.network) def test_modified_nodecons(self): """Diff: modified nodecons.""" lst = sorted(self.diff.modified_nodecons, key=lambda x: x.rule) self.assertEqual(2, len(lst)) # changed IPv4 nodecon, added_context, removed_context = lst[0] self.assertEqual(IPv4Network("123.0.0.0/8"), nodecon.network) self.assertEqual("modified_change_level:object_r:system:s2:c0", added_context) self.assertEqual("modified_change_level:object_r:system:s2:c1", removed_context) # changed IPv6 nodecon, added_context, removed_context = lst[1] self.assertEqual(IPv6Network("ff03::/62"), nodecon.network) self.assertEqual("modified_change_level:object_r:system:s2:c1", added_context) self.assertEqual("modified_change_level:object_r:system:s2:c0.c1", removed_context) # # Policy capabilities # def test_added_polcaps(self): """Diff: added polcaps.""" self.assertSetEqual(set(["always_check_network"]), self.diff.added_polcaps) def test_removed_polcaps(self): """Diff: removed polcaps.""" self.assertSetEqual(set(["network_peer_controls"]), self.diff.removed_polcaps) # # portcons # def test_added_portcons(self): """Diff: added portcons.""" lst = sorted(self.diff.added_portcons) self.assertEqual(2, len(lst)) portcon = lst[0] self.assertEqual(PortconProtocol.tcp, portcon.protocol) self.assertTupleEqual((2024, 2026), portcon.ports) portcon = lst[1] self.assertEqual(PortconProtocol.udp, portcon.protocol) self.assertTupleEqual((2024, 2024), portcon.ports) def test_removed_portcons(self): """Diff: removed portcons.""" lst = sorted(self.diff.removed_portcons) self.assertEqual(2, len(lst)) portcon = lst[0] self.assertEqual(PortconProtocol.tcp, portcon.protocol) self.assertTupleEqual((1024, 1026), portcon.ports) portcon = lst[1] self.assertEqual(PortconProtocol.udp, portcon.protocol) self.assertTupleEqual((1024, 1024), portcon.ports) def test_modified_portcons(self): """Diff: modified portcons.""" lst = sorted(self.diff.modified_portcons, key=lambda x: x.rule) self.assertEqual(2, len(lst)) portcon, added_context, removed_context = lst[0] self.assertEqual(PortconProtocol.tcp, portcon.protocol) self.assertTupleEqual((3024, 3026), portcon.ports) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) portcon, added_context, removed_context = lst[1] self.assertEqual(PortconProtocol.udp, portcon.protocol) self.assertTupleEqual((3024, 3024), portcon.ports) self.assertEqual("added_user:object_r:system:s1", added_context) self.assertEqual("removed_user:object_r:system:s0", removed_context) # # defaults # def test_added_defaults(self): """Diff: added defaults.""" lst = sorted(self.diff.added_defaults) self.assertEqual(2, len(lst)) default = lst[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow2", default.tclass) default = lst[1] self.assertEqual(DRT.default_user, default.ruletype) self.assertEqual("infoflow2", default.tclass) def test_removed_defaults(self): """Diff: removed defaults.""" lst = sorted(self.diff.removed_defaults) self.assertEqual(2, len(lst)) default = lst[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow3", default.tclass) default = lst[1] self.assertEqual(DRT.default_role, default.ruletype) self.assertEqual("infoflow3", default.tclass) def test_modified_defaults(self): """Diff: modified defaults.""" lst = sorted(self.diff.modified_defaults, key=lambda x: x.rule) self.assertEqual(4, len(lst)) default, added_default, removed_default, added_range, removed_range = lst[0] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow4", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertIsNone(added_range) self.assertIsNone(removed_range) default, added_default, removed_default, added_range, removed_range = lst[1] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow5", default.tclass) self.assertIsNone(added_default) self.assertIsNone(removed_default) self.assertEqual(DRV.high, added_range) self.assertEqual(DRV.low, removed_range) default, added_default, removed_default, added_range, removed_range = lst[2] self.assertEqual(DRT.default_range, default.ruletype) self.assertEqual("infoflow6", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertEqual(DRV.low, added_range) self.assertEqual(DRV.high, removed_range) default, added_default, removed_default, added_range, removed_range = lst[3] self.assertEqual(DRT.default_type, default.ruletype) self.assertEqual("infoflow4", default.tclass) self.assertEqual(DV.target, added_default) self.assertEqual(DV.source, removed_default) self.assertIsNone(added_range) self.assertIsNone(removed_range) # # constrains # def test_added_constrains(self): """Diff: added constrains.""" lst = sorted(self.diff.added_constrains) self.assertEqual(2, len(lst)) constrain = lst[0] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow3", constrain.tclass) self.assertSetEqual(set(["null"]), constrain.perms) self.assertEqual(["u1", "u2", "!="], constrain.expression) constrain = lst[1] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow5", constrain.tclass) self.assertSetEqual(set(["hi_r"]), constrain.perms) self.assertEqual( ['u1', 'u2', '==', 'r1', 'r2', '==', 'and', 't1', set(["system"]), '!=', 'or'], constrain.expression) def test_removed_constrains(self): """Diff: removed constrains.""" lst = sorted(self.diff.removed_constrains) self.assertEqual(2, len(lst)) constrain = lst[0] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow4", constrain.tclass) self.assertSetEqual(set(["hi_w"]), constrain.perms) self.assertEqual(["u1", "u2", "!="], constrain.expression) constrain = lst[1] self.assertEqual(CRT.constrain, constrain.ruletype) self.assertEqual("infoflow5", constrain.tclass) self.assertSetEqual(set(["hi_r"]), constrain.perms) self.assertEqual( ['u1', 'u2', '==', 'r1', 'r2', '==', 'and', 't1', set(["system"]), '==', 'or'], constrain.expression) # # mlsconstrains # def test_added_mlsconstrains(self): """Diff: added mlsconstrains.""" lst = sorted(self.diff.added_mlsconstrains) self.assertEqual(2, len(lst)) mlsconstrain = lst[0] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow3", mlsconstrain.tclass) self.assertSetEqual(set(["null"]), mlsconstrain.perms) self.assertEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'domby', 'and', 't1', set(["mls_exempt"]), '!=', 'or'], mlsconstrain.expression) mlsconstrain = lst[1] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow5", mlsconstrain.tclass) self.assertSetEqual(set(["hi_r"]), mlsconstrain.perms) self.assertEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'incomp', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.expression) def test_removed_mlsconstrains(self): """Diff: removed mlsconstrains.""" lst = sorted(self.diff.removed_mlsconstrains) self.assertEqual(2, len(lst)) mlsconstrain = lst[0] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow4", mlsconstrain.tclass) self.assertSetEqual(set(["hi_w"]), mlsconstrain.perms) self.assertEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'domby', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.expression) mlsconstrain = lst[1] self.assertEqual(CRT.mlsconstrain, mlsconstrain.ruletype) self.assertEqual("infoflow5", mlsconstrain.tclass) self.assertSetEqual(set(["hi_r"]), mlsconstrain.perms) self.assertEqual( ['l1', 'l2', 'domby', 'h1', 'h2', 'dom', 'and', 't1', set(["mls_exempt"]), '==', 'or'], mlsconstrain.expression) # # validatetrans # def test_added_validatetrans(self): """Diff: added validatetrans.""" lst = sorted(self.diff.added_validatetrans) self.assertEqual(2, len(lst)) validatetrans = lst[0] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow3", validatetrans.tclass) self.assertEqual( ['t1', 't2', '==', 't3', set(["system"]), '==', 'or'], validatetrans.expression) validatetrans = lst[1] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow5", validatetrans.tclass) self.assertEqual( ['u1', 'u2', '!=', 'r1', 'r2', '==', 'and', 't3', set(["system"]), '==', 'or'], validatetrans.expression) def test_removed_validatetrans(self): """Diff: removed validatetrans.""" lst = sorted(self.diff.removed_validatetrans) self.assertEqual(2, len(lst)) validatetrans = lst[0] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow4", validatetrans.tclass) self.assertEqual( ['u1', 'u2', '==', 't3', set(["system"]), '==', 'or'], validatetrans.expression) validatetrans = lst[1] self.assertEqual(CRT.validatetrans, validatetrans.ruletype) self.assertEqual("infoflow5", validatetrans.tclass) self.assertEqual( ['u1', 'u2', '==', 'r1', 'r2', '!=', 'and', 't3', set(["system"]), '==', 'or'], validatetrans.expression) # # mlsvalidatetrans # def test_added_mlsvalidatetrans(self): """Diff: added mlsvalidatetrans.""" lst = sorted(self.diff.added_mlsvalidatetrans) self.assertEqual(2, len(lst)) mlsvalidatetrans = lst[0] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow3", mlsvalidatetrans.tclass) self.assertEqual( ['l1', 'l2', '==', 'h1', 'h2', '==', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.expression) mlsvalidatetrans = lst[1] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow5", mlsvalidatetrans.tclass) self.assertEqual( ['l1', 'l2', 'incomp', 'h1', 'h2', 'domby', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.expression) def test_removed_mlsvalidatetrans(self): """Diff: removed mlsvalidatetrans.""" lst = sorted(self.diff.removed_mlsvalidatetrans) self.assertEqual(2, len(lst)) mlsvalidatetrans = lst[0] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow4", mlsvalidatetrans.tclass) self.assertEqual( ['l1', 'l2', '==', 'h1', 'h2', '==', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.expression) mlsvalidatetrans = lst[1] self.assertEqual(CRT.mlsvalidatetrans, mlsvalidatetrans.ruletype) self.assertEqual("infoflow5", mlsvalidatetrans.tclass) self.assertEqual( ['l1', 'l2', 'dom', 'h1', 'h2', 'dom', 'and', 't3', set(["mls_exempt"]), '==', 'or'], mlsvalidatetrans.expression) # # typebounds # def test_added_typebounds(self): """Diff: added typebounds.""" lst = sorted(self.diff.added_typebounds) self.assertEqual(1, len(lst)) bounds = lst[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("added_parent", bounds.parent) self.assertEqual("added_child", bounds.child) def test_removed_typebounds(self): """Diff: removed typebounds.""" lst = sorted(self.diff.removed_typebounds) self.assertEqual(1, len(lst)) bounds = lst[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("removed_parent", bounds.parent) self.assertEqual("removed_child", bounds.child) def test_modified_typebounds(self): """Diff: modified typebounds.""" lst = sorted(self.diff.modified_typebounds, key=lambda x: x.rule) self.assertEqual(1, len(lst)) bounds, added_bound, removed_bound = lst[0] self.assertEqual(BRT.typebounds, bounds.ruletype) self.assertEqual("mod_child", bounds.child) self.assertEqual("mod_parent_added", added_bound) self.assertEqual("mod_parent_removed", removed_bound) # # Allowxperm rules # def test_added_allowxperm_rules(self): """Diff: added allowxperm rules.""" rules = sorted(self.diff.added_allowxperms) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.allowxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") # added rule with existing types self.validate_rule(rules[1], TRT.allowxperm, "ax_added_rule_source", "ax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_allowxperm_rules(self): """Diff: removed allowxperm rules.""" rules = sorted(self.diff.removed_allowxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.allowxperm, "ax_removed_rule_source", "ax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.allowxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_allowxperm_rules(self): """Diff: modified allowxperm rules.""" lst = sorted(self.diff.modified_allowxperms, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_add_perms", rule.source) self.assertEqual("ax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_add_remove_perms", rule.source) self.assertEqual("ax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.allowxperm, rule.ruletype) self.assertEqual("ax_modified_rule_remove_perms", rule.source) self.assertEqual("ax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Auditallowxperm rules # def test_added_auditallowxperm_rules(self): """Diff: added auditallowxperm rules.""" rules = sorted(self.diff.added_auditallowxperms) self.assertEqual(2, len(rules)) # added rule with existing types self.validate_rule(rules[0], TRT.auditallowxperm, "aax_added_rule_source", "aax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # added rule with new type self.validate_rule(rules[1], TRT.auditallowxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_removed_auditallowxperm_rules(self): """Diff: removed auditallowxperm rules.""" rules = sorted(self.diff.removed_auditallowxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.auditallowxperm, "aax_removed_rule_source", "aax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.auditallowxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_auditallowxperm_rules(self): """Diff: modified auditallowxperm rules.""" lst = sorted(self.diff.modified_auditallowxperms, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_add_perms", rule.source) self.assertEqual("aax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_add_remove_perms", rule.source) self.assertEqual("aax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.auditallowxperm, rule.ruletype) self.assertEqual("aax_modified_rule_remove_perms", rule.source) self.assertEqual("aax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Neverallowxperm rules # def test_added_neverallowxperm_rules(self): """Diff: added neverallowxperm rules.""" self.assertFalse(self.diff.added_neverallowxperms) # changed after dropping source policy support # rules = sorted(self.diff.added_neverallowxperms) # self.assertEqual(2, len(rules)) # # # added rule with new type # self.validate_rule(rules[0], TRT.neverallowxperm, "added_type", "added_type", "infoflow7", # set([0x0009]), xperm="ioctl") # # # added rule with existing types # self.validate_rule(rules[1], TRT.neverallowxperm, "nax_added_rule_source", # "nax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_neverallowxperm_rules(self): """Diff: removed neverallowxperm rules.""" self.assertFalse(self.diff.removed_neverallowxperms) # changed after dropping source policy support # rules = sorted(self.diff.removed_neverallowxperms) # self.assertEqual(2, len(rules)) # # # removed rule with existing types # self.validate_rule(rules[0], TRT.neverallowxperm, "nax_removed_rule_source", # "nax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # # # removed rule with new type # self.validate_rule(rules[1], TRT.neverallowxperm, "removed_type", "removed_type", # "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_neverallowxperm_rules(self): """Diff: modified neverallowxperm rules.""" self.assertFalse(self.diff.modified_neverallowxperms) # changed after dropping source policy support # l = sorted(self.diff.modified_neverallowxperms, key=lambda x: x.rule) # self.assertEqual(3, len(l)) # # # add permissions # rule, added_perms, removed_perms, matched_perms = l[0] # self.assertEqual(TRT.neverallowxperm, rule.ruletype) # self.assertEqual("nax_modified_rule_add_perms", rule.source) # self.assertEqual("nax_modified_rule_add_perms", rule.target) # self.assertEqual("infoflow", rule.tclass) # self.assertSetEqual(set([0x000f]), added_perms) # self.assertFalse(removed_perms) # self.assertSetEqual(set([0x0004]), matched_perms) # # # add and remove permissions # rule, added_perms, removed_perms, matched_perms = l[1] # self.assertEqual(TRT.neverallowxperm, rule.ruletype) # self.assertEqual("nax_modified_rule_add_remove_perms", rule.source) # self.assertEqual("nax_modified_rule_add_remove_perms", rule.target) # self.assertEqual("infoflow2", rule.tclass) # self.assertSetEqual(set([0x0006]), added_perms) # self.assertSetEqual(set([0x0007]), removed_perms) # self.assertSetEqual(set([0x0008]), matched_perms) # # # remove permissions # rule, added_perms, removed_perms, matched_perms = l[2] # self.assertEqual(TRT.neverallowxperm, rule.ruletype) # self.assertEqual("nax_modified_rule_remove_perms", rule.source) # self.assertEqual("nax_modified_rule_remove_perms", rule.target) # self.assertEqual("infoflow", rule.tclass) # self.assertFalse(added_perms) # self.assertSetEqual(set([0x0006]), removed_perms) # self.assertSetEqual(set([0x0005]), matched_perms) # # Dontauditxperm rules # def test_added_dontauditxperm_rules(self): """Diff: added dontauditxperm rules.""" rules = sorted(self.diff.added_dontauditxperms) self.assertEqual(2, len(rules)) # added rule with new type self.validate_rule(rules[0], TRT.dontauditxperm, "added_type", "added_type", "infoflow7", set([0x0009]), xperm="ioctl") # added rule with existing types self.validate_rule(rules[1], TRT.dontauditxperm, "dax_added_rule_source", "dax_added_rule_target", "infoflow", set([0x0002]), xperm="ioctl") def test_removed_dontauditxperm_rules(self): """Diff: removed dontauditxperm rules.""" rules = sorted(self.diff.removed_dontauditxperms) self.assertEqual(2, len(rules)) # removed rule with existing types self.validate_rule(rules[0], TRT.dontauditxperm, "dax_removed_rule_source", "dax_removed_rule_target", "infoflow", set([0x0002]), xperm="ioctl") # removed rule with new type self.validate_rule(rules[1], TRT.dontauditxperm, "removed_type", "removed_type", "infoflow7", set([0x0009]), xperm="ioctl") def test_modified_dontauditxperm_rules(self): """Diff: modified dontauditxperm rules.""" lst = sorted(self.diff.modified_dontauditxperms, key=lambda x: x.rule) self.assertEqual(3, len(lst)) # add permissions rule, added_perms, removed_perms, matched_perms = lst[0] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_add_perms", rule.source) self.assertEqual("dax_modified_rule_add_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertSetEqual(set([0x000f]), added_perms) self.assertFalse(removed_perms) self.assertSetEqual(set([0x0004]), matched_perms) # add and remove permissions rule, added_perms, removed_perms, matched_perms = lst[1] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_add_remove_perms", rule.source) self.assertEqual("dax_modified_rule_add_remove_perms", rule.target) self.assertEqual("infoflow2", rule.tclass) self.assertSetEqual(set([0x0006]), added_perms) self.assertSetEqual(set([0x0007]), removed_perms) self.assertSetEqual(set([0x0008]), matched_perms) # remove permissions rule, added_perms, removed_perms, matched_perms = lst[2] self.assertEqual(TRT.dontauditxperm, rule.ruletype) self.assertEqual("dax_modified_rule_remove_perms", rule.source) self.assertEqual("dax_modified_rule_remove_perms", rule.target) self.assertEqual("infoflow", rule.tclass) self.assertFalse(added_perms) self.assertSetEqual(set([0x0006]), removed_perms) self.assertSetEqual(set([0x0005]), matched_perms) # # Ibendportcon statements # def test_added_ibendportcons(self): """Diff: added ibendportcon statements.""" rules = sorted(self.diff.added_ibendportcons) self.assertEqual(1, len(rules)) self.assertEqual("add", rules[0].name) self.assertEqual(23, rules[0].port) self.assertEqual("system:system:system:s0", rules[0].context) def test_removed_ibendportcons(self): """Diff: removed ibendportcon statements.""" rules = sorted(self.diff.removed_ibendportcons) self.assertEqual(1, len(rules)) self.assertEqual("removed", rules[0].name) self.assertEqual(7, rules[0].port) self.assertEqual("system:system:system:s0", rules[0].context) def test_modified_ibendportcons(self): """Diff: modified ibendportcon statements""" rules = sorted(self.diff.modified_ibendportcons) self.assertEqual(1, len(rules)) rule, added, removed = rules[0] self.assertEqual("modified", rule.name) self.assertEqual(13, rule.port) self.assertEqual("modified_change_level:object_r:system:s2", added) self.assertEqual("modified_change_level:object_r:system:s2:c0.c1", removed) # # Ibpkeycon statements # def test_added_ibpkeycons(self): """Diff: added ibpkeycon statements.""" rules = sorted(self.diff.added_ibpkeycons) self.assertEqual(2, len(rules)) rule = rules[0] self.assertEqual(IPv6Address("beef::"), rule.subnet_prefix) self.assertEqual(0xe, rule.pkeys.low) self.assertEqual(0xe, rule.pkeys.high) self.assertEqual("system:system:system:s0", rule.context) rule = rules[1] self.assertEqual(IPv6Address("dead::"), rule.subnet_prefix) self.assertEqual(0xbeef, rule.pkeys.low) self.assertEqual(0xdead, rule.pkeys.high) self.assertEqual("system:system:system:s0", rule.context) def test_removed_ibpkeycons(self): """Diff: removed ibpkeycon statements.""" rules = sorted(self.diff.removed_ibpkeycons) self.assertEqual(2, len(rules)) rule = rules[0] self.assertEqual(IPv6Address("dccc::"), rule.subnet_prefix) self.assertEqual(0xc, rule.pkeys.low) self.assertEqual(0xc, rule.pkeys.high) self.assertEqual("system:system:system:s0", rule.context) rule = rules[1] self.assertEqual(IPv6Address("feee::"), rule.subnet_prefix) self.assertEqual(0xaaaa, rule.pkeys.low) self.assertEqual(0xbbbb, rule.pkeys.high) self.assertEqual("system:system:system:s0", rule.context) def test_modified_ibpkeycons(self): """Diff: modified ibpkeycon statements""" rules = sorted(self.diff.modified_ibpkeycons) self.assertEqual(2, len(rules)) rule, added, removed = rules[0] self.assertEqual(IPv6Address("aaaa::"), rule.subnet_prefix) self.assertEqual(0xcccc, rule.pkeys.low) self.assertEqual(0xdddd, rule.pkeys.high) self.assertEqual("modified_change_level:object_r:system:s2:c0", added) self.assertEqual("modified_change_level:object_r:system:s2:c1", removed) rule, added, removed = rules[1] self.assertEqual(IPv6Address("bbbb::"), rule.subnet_prefix) self.assertEqual(0xf, rule.pkeys.low) self.assertEqual(0xf, rule.pkeys.high) self.assertEqual("modified_change_level:object_r:system:s2:c1", added) self.assertEqual("modified_change_level:object_r:system:s2:c0.c1", removed) class PolicyDifferenceRmIsidTest(unittest.TestCase): """ Policy difference test for removed initial SID. Since initial SID names are fixed (they don't exist in the binary policy) this cannot be in the above test suite. """ @classmethod def setUpClass(cls): cls.p_left = compile_policy("tests/diff_left.conf") cls.p_right = compile_policy("tests/diff_right_rmisid.conf") cls.diff = PolicyDifference(cls.p_left, cls.p_right) @classmethod def tearDownClass(cls): os.unlink(cls.p_left.path) os.unlink(cls.p_right.path) def test_removed_initialsids(self): """Diff: removed initialsids.""" self.assertSetEqual(set(["file"]), self.diff.removed_initialsids) class PolicyDifferenceTestNoDiff(unittest.TestCase): """Policy difference test with no policy differences.""" @classmethod def setUpClass(cls): cls.p_left = compile_policy("tests/diff_left.conf") cls.p_right = compile_policy("tests/diff_left.conf") cls.diff = PolicyDifference(cls.p_left, cls.p_right) @classmethod def tearDownClass(cls): os.unlink(cls.p_left.path) os.unlink(cls.p_right.path) def test_added_types(self): """NoDiff: no added types""" self.assertFalse(self.diff.added_types) def test_removed_types(self): """NoDiff: no removed types""" self.assertFalse(self.diff.removed_types) def test_modified_types(self): """NoDiff: no modified types""" self.assertFalse(self.diff.modified_types) def test_added_roles(self): """NoDiff: no added roles.""" self.assertFalse(self.diff.added_roles) def test_removed_roles(self): """NoDiff: no removed roles.""" self.assertFalse(self.diff.removed_roles) def test_modified_roles(self): """NoDiff: no modified roles.""" self.assertFalse(self.diff.modified_roles) def test_added_commons(self): """NoDiff: no added commons.""" self.assertFalse(self.diff.added_commons) def test_removed_commons(self): """NoDiff: no removed commons.""" self.assertFalse(self.diff.removed_commons) def test_modified_commons(self): """NoDiff: no modified commons.""" self.assertFalse(self.diff.modified_commons) def test_added_classes(self): """NoDiff: no added classes.""" self.assertFalse(self.diff.added_classes) def test_removed_classes(self): """NoDiff: no removed classes.""" self.assertFalse(self.diff.removed_classes) def test_modified_classes(self): """NoDiff: no modified classes.""" self.assertFalse(self.diff.modified_classes) def test_added_allows(self): """NoDiff: no added allow rules.""" self.assertFalse(self.diff.added_allows) def test_removed_allows(self): """NoDiff: no removed allow rules.""" self.assertFalse(self.diff.removed_allows) def test_modified_allows(self): """NoDiff: no modified allow rules.""" self.assertFalse(self.diff.modified_allows) def test_added_auditallows(self): """NoDiff: no added auditallow rules.""" self.assertFalse(self.diff.added_auditallows) def test_removed_auditallows(self): """NoDiff: no removed auditallow rules.""" self.assertFalse(self.diff.removed_auditallows) def test_modified_auditallows(self): """NoDiff: no modified auditallow rules.""" self.assertFalse(self.diff.modified_auditallows) def test_added_neverallows(self): """NoDiff: no added neverallow rules.""" self.assertFalse(self.diff.added_neverallows) def test_removed_neverallows(self): """NoDiff: no removed neverallow rules.""" self.assertFalse(self.diff.removed_neverallows) def test_modified_neverallows(self): """NoDiff: no modified neverallow rules.""" self.assertFalse(self.diff.modified_neverallows) def test_added_dontaudits(self): """NoDiff: no added dontaudit rules.""" self.assertFalse(self.diff.added_dontaudits) def test_removed_dontaudits(self): """NoDiff: no removed dontaudit rules.""" self.assertFalse(self.diff.removed_dontaudits) def test_modified_dontaudits(self): """NoDiff: no modified dontaudit rules.""" self.assertFalse(self.diff.modified_dontaudits) def test_added_type_transitions(self): """NoDiff: no added type_transition rules.""" self.assertFalse(self.diff.added_type_transitions) def test_removed_type_transitions(self): """NoDiff: no removed type_transition rules.""" self.assertFalse(self.diff.removed_type_transitions) def test_modified_type_transitions(self): """NoDiff: no modified type_transition rules.""" self.assertFalse(self.diff.modified_type_transitions) def test_added_type_changes(self): """NoDiff: no added type_change rules.""" self.assertFalse(self.diff.added_type_changes) def test_removed_type_changes(self): """NoDiff: no removed type_change rules.""" self.assertFalse(self.diff.removed_type_changes) def test_modified_type_changes(self): """NoDiff: no modified type_change rules.""" self.assertFalse(self.diff.modified_type_changes) def test_added_type_members(self): """NoDiff: no added type_member rules.""" self.assertFalse(self.diff.added_type_members) def test_removed_type_members(self): """NoDiff: no removed type_member rules.""" self.assertFalse(self.diff.removed_type_members) def test_modified_type_members(self): """NoDiff: no modified type_member rules.""" self.assertFalse(self.diff.modified_type_members) def test_added_range_transitions(self): """NoDiff: no added range_transition rules.""" self.assertFalse(self.diff.added_range_transitions) def test_removed_range_transitions(self): """NoDiff: no removed range_transition rules.""" self.assertFalse(self.diff.removed_range_transitions) def test_modified_range_transitions(self): """NoDiff: no modified range_transition rules.""" self.assertFalse(self.diff.modified_range_transitions) def test_added_role_allows(self): """NoDiff: no added role_allow rules.""" self.assertFalse(self.diff.added_role_allows) def test_removed_role_allows(self): """NoDiff: no removed role_allow rules.""" self.assertFalse(self.diff.removed_role_allows) def test_added_role_transitions(self): """NoDiff: no added role_transition rules.""" self.assertFalse(self.diff.added_role_transitions) def test_removed_role_transitions(self): """NoDiff: no removed role_transition rules.""" self.assertFalse(self.diff.removed_role_transitions) def test_modified_role_transitions(self): """NoDiff: no modified role_transition rules.""" self.assertFalse(self.diff.modified_role_transitions) def test_added_users(self): """NoDiff: no added users.""" self.assertFalse(self.diff.added_users) def test_removed_users(self): """NoDiff: no removed users.""" self.assertFalse(self.diff.removed_users) def test_modified_users(self): """NoDiff: no modified user rules.""" self.assertFalse(self.diff.modified_users) def test_added_type_attributes(self): """NoDiff: no added type attribute.""" self.assertFalse(self.diff.added_type_attributes) def test_removed_type_attributes(self): """NoDiff: no removed type attributes.""" self.assertFalse(self.diff.removed_type_attributes) def test_modified_type_attributes(self): """NoDiff: no modified type attributes.""" self.assertFalse(self.diff.modified_type_attributes) def test_added_booleans(self): """NoDiff: no added booleans.""" self.assertFalse(self.diff.added_booleans) def test_removed_booleans(self): """NoDiff: no removed booleans.""" self.assertFalse(self.diff.removed_booleans) def test_modified_booleans(self): """NoDiff: no modified booleans.""" self.assertFalse(self.diff.modified_booleans) def test_added_categories(self): """NoDiff: no added categories.""" self.assertFalse(self.diff.added_categories) def test_removed_categories(self): """NoDiff: no removed categories.""" self.assertFalse(self.diff.removed_categories) def test_modified_categories(self): """NoDiff: no modified categories.""" self.assertFalse(self.diff.modified_categories) def test_added_sensitivities(self): """NoDiff: no added sensitivities.""" self.assertFalse(self.diff.added_sensitivities) def test_removed_sensitivities(self): """NoDiff: no removed sensitivities.""" self.assertFalse(self.diff.removed_sensitivities) def test_modified_sensitivities(self): """NoDiff: no modified sensitivities.""" self.assertFalse(self.diff.modified_sensitivities) def test_added_initialsids(self): """NoDiff: no added initialsids.""" self.assertFalse(self.diff.added_initialsids) def test_removed_initialsids(self): """NoDiff: no removed initialsids.""" self.assertFalse(self.diff.removed_initialsids) def test_modified_initialsids(self): """NoDiff: no modified initialsids.""" self.assertFalse(self.diff.modified_initialsids) def test_added_fs_uses(self): """NoDiff: no added fs_uses.""" self.assertFalse(self.diff.added_fs_uses) def test_removed_fs_uses(self): """NoDiff: no removed fs_uses.""" self.assertFalse(self.diff.removed_fs_uses) def test_modified_fs_uses(self): """NoDiff: no modified fs_uses.""" self.assertFalse(self.diff.modified_fs_uses) def test_added_genfscons(self): """NoDiff: no added genfscons.""" self.assertFalse(self.diff.added_genfscons) def test_removed_genfscons(self): """NoDiff: no removed genfscons.""" self.assertFalse(self.diff.removed_genfscons) def test_modified_genfscons(self): """NoDiff: no modified genfscons.""" self.assertFalse(self.diff.modified_genfscons) def test_added_levels(self): """NoDiff: no added levels.""" self.assertFalse(self.diff.added_levels) def test_removed_levels(self): """NoDiff: no removed levels.""" self.assertFalse(self.diff.removed_levels) def test_modified_levels(self): """NoDiff: no modified levels.""" self.assertFalse(self.diff.modified_levels) def test_added_netifcons(self): """NoDiff: no added netifcons.""" self.assertFalse(self.diff.added_netifcons) def test_removed_netifcons(self): """NoDiff: no removed netifcons.""" self.assertFalse(self.diff.removed_netifcons) def test_modified_netifcons(self): """NoDiff: no modified netifcons.""" self.assertFalse(self.diff.modified_netifcons) def test_added_nodecons(self): """NoDiff: no added nodecons.""" self.assertFalse(self.diff.added_nodecons) def test_removed_nodecons(self): """NoDiff: no removed nodecons.""" self.assertFalse(self.diff.removed_nodecons) def test_modified_nodecons(self): """NoDiff: no modified nodecons.""" self.assertFalse(self.diff.modified_nodecons) def test_added_polcaps(self): """NoDiff: no added polcaps.""" self.assertFalse(self.diff.added_polcaps) def test_removed_polcaps(self): """NoDiff: no removed polcaps.""" self.assertFalse(self.diff.removed_polcaps) def test_added_portcons(self): """NoDiff: no added portcons.""" self.assertFalse(self.diff.added_portcons) def test_removed_portcons(self): """NoDiff: no removed portcons.""" self.assertFalse(self.diff.removed_portcons) def test_modified_portcons(self): """NoDiff: no modified portcons.""" self.assertFalse(self.diff.modified_portcons) def test_modified_properties(self): """NoDiff: no modified properties.""" self.assertFalse(self.diff.modified_properties) def test_added_defaults(self): """NoDiff: no added defaults.""" self.assertFalse(self.diff.added_defaults) def test_removed_defaults(self): """NoDiff: no removed defaults.""" self.assertFalse(self.diff.removed_defaults) def test_modified_defaults(self): """NoDiff: no modified defaults.""" self.assertFalse(self.diff.modified_defaults) def test_added_constrains(self): """NoDiff: no added constrains.""" self.assertFalse(self.diff.added_constrains) def test_removed_constrains(self): """NoDiff: no removed constrains.""" self.assertFalse(self.diff.removed_constrains) def test_added_mlsconstrains(self): """NoDiff: no added mlsconstrains.""" self.assertFalse(self.diff.added_mlsconstrains) def test_removed_mlsconstrains(self): """NoDiff: no removed mlsconstrains.""" self.assertFalse(self.diff.removed_mlsconstrains) def test_added_validatetrans(self): """NoDiff: no added validatetrans.""" self.assertFalse(self.diff.added_validatetrans) def test_removed_validatetrans(self): """NoDiff: no removed validatetrans.""" self.assertFalse(self.diff.removed_validatetrans) def test_added_mlsvalidatetrans(self): """NoDiff: no added mlsvalidatetrans.""" self.assertFalse(self.diff.added_mlsvalidatetrans) def test_removed_mlsvalidatetrans(self): """NoDiff: no removed mlsvalidatetrans.""" self.assertFalse(self.diff.removed_mlsvalidatetrans) def test_added_typebounds(self): """NoDiff: no added typebounds.""" self.assertFalse(self.diff.added_typebounds) def test_removed_typebounds(self): """NoDiff: no removed typebounds.""" self.assertFalse(self.diff.removed_typebounds) def test_modified_typebounds(self): """NoDiff: no modified typebounds.""" self.assertFalse(self.diff.modified_typebounds) def test_added_allowxperms(self): """NoDiff: no added allowxperm rules.""" self.assertFalse(self.diff.added_allowxperms) def test_removed_allowxperms(self): """NoDiff: no removed allowxperm rules.""" self.assertFalse(self.diff.removed_allowxperms) def test_modified_allowxperms(self): """NoDiff: no modified allowxperm rules.""" self.assertFalse(self.diff.modified_allowxperms) def test_added_auditallowxperms(self): """NoDiff: no added auditallowxperm rules.""" self.assertFalse(self.diff.added_auditallowxperms) def test_removed_auditallowxperms(self): """NoDiff: no removed auditallowxperm rules.""" self.assertFalse(self.diff.removed_auditallowxperms) def test_modified_auditallowxperms(self): """NoDiff: no modified auditallowxperm rules.""" self.assertFalse(self.diff.modified_auditallowxperms) def test_added_neverallowxperms(self): """NoDiff: no added neverallowxperm rules.""" self.assertFalse(self.diff.added_neverallowxperms) def test_removed_neverallowxperms(self): """NoDiff: no removed neverallowxperm rules.""" self.assertFalse(self.diff.removed_neverallowxperms) def test_modified_neverallowxperms(self): """NoDiff: no modified neverallowxperm rules.""" self.assertFalse(self.diff.modified_neverallowxperms) def test_added_dontauditxperms(self): """NoDiff: no added dontauditxperm rules.""" self.assertFalse(self.diff.added_dontauditxperms) def test_removed_dontauditxperms(self): """NoDiff: no removed dontauditxperm rules.""" self.assertFalse(self.diff.removed_dontauditxperms) def test_modified_dontauditxperms(self): """NoDiff: no modified dontauditxperm rules.""" self.assertFalse(self.diff.modified_dontauditxperms) def test_added_ibendportcons(self): """NoDiff: no added ibendportcon rules.""" self.assertFalse(self.diff.added_ibendportcons) def test_removed_ibendportcons(self): """NoDiff: no removed ibendportcon rules.""" self.assertFalse(self.diff.removed_ibendportcons) def test_modified_ibendportcons(self): """NoDiff: no modified ibendportcon rules.""" self.assertFalse(self.diff.modified_ibendportcons) def test_added_ibpkeycons(self): """NoDiff: no added ibpkeycon rules.""" self.assertFalse(self.diff.added_ibpkeycons) def test_removed_ibpkeycons(self): """NoDiff: no removed ibpkeycon rules.""" self.assertFalse(self.diff.removed_ibpkeycons) def test_modified_ibpkeycons(self): """NoDiff: no modified ibpkeycon rules.""" self.assertFalse(self.diff.modified_ibpkeycons) class PolicyDifferenceTestMLStoStandard(unittest.TestCase): """ Policy difference test between MLS and standard (non-MLS) policy. The left policy is an MLS policy. The right policy is identical to the left policy, except with MLS disabled. """ @classmethod def setUpClass(cls): cls.p_left = compile_policy("tests/diff_left.conf") cls.p_right = compile_policy("tests/diff_left_standard.conf", mls=False) cls.diff = PolicyDifference(cls.p_left, cls.p_right) @classmethod def tearDownClass(cls): os.unlink(cls.p_left.path) os.unlink(cls.p_right.path) def test_added_types(self): """MLSvsStandardDiff: no added types""" self.assertFalse(self.diff.added_types) def test_removed_types(self): """MLSvsStandardDiff: no removed types""" self.assertFalse(self.diff.removed_types) def test_modified_types(self): """MLSvsStandardDiff: no modified types""" self.assertFalse(self.diff.modified_types) def test_added_roles(self): """MLSvsStandardDiff: no added roles.""" self.assertFalse(self.diff.added_roles) def test_removed_roles(self): """MLSvsStandardDiff: no removed roles.""" self.assertFalse(self.diff.removed_roles) def test_modified_roles(self): """MLSvsStandardDiff: no modified roles.""" self.assertFalse(self.diff.modified_roles) def test_added_commons(self): """MLSvsStandardDiff: no added commons.""" self.assertFalse(self.diff.added_commons) def test_removed_commons(self): """MLSvsStandardDiff: no removed commons.""" self.assertFalse(self.diff.removed_commons) def test_modified_commons(self): """MLSvsStandardDiff: no modified commons.""" self.assertFalse(self.diff.modified_commons) def test_added_classes(self): """MLSvsStandardDiff: no added classes.""" self.assertFalse(self.diff.added_classes) def test_removed_classes(self): """MLSvsStandardDiff: no removed classes.""" self.assertFalse(self.diff.removed_classes) def test_modified_classes(self): """MLSvsStandardDiff: no modified classes.""" self.assertFalse(self.diff.modified_classes) def test_added_allows(self): """MLSvsStandardDiff: no added allow rules.""" self.assertFalse(self.diff.added_allows) def test_removed_allows(self): """MLSvsStandardDiff: no removed allow rules.""" self.assertFalse(self.diff.removed_allows) def test_modified_allows(self): """MLSvsStandardDiff: no modified allow rules.""" self.assertFalse(self.diff.modified_allows) def test_added_auditallows(self): """MLSvsStandardDiff: no added auditallow rules.""" self.assertFalse(self.diff.added_auditallows) def test_removed_auditallows(self): """MLSvsStandardDiff: no removed auditallow rules.""" self.assertFalse(self.diff.removed_auditallows) def test_modified_auditallows(self): """MLSvsStandardDiff: no modified auditallow rules.""" self.assertFalse(self.diff.modified_auditallows) def test_added_neverallows(self): """MLSvsStandardDiff: no added neverallow rules.""" self.assertFalse(self.diff.added_neverallows) def test_removed_neverallows(self): """MLSvsStandardDiff: no removed neverallow rules.""" self.assertFalse(self.diff.removed_neverallows) def test_modified_neverallows(self): """MLSvsStandardDiff: no modified neverallow rules.""" self.assertFalse(self.diff.modified_neverallows) def test_added_dontaudits(self): """MLSvsStandardDiff: no added dontaudit rules.""" self.assertFalse(self.diff.added_dontaudits) def test_removed_dontaudits(self): """MLSvsStandardDiff: no removed dontaudit rules.""" self.assertFalse(self.diff.removed_dontaudits) def test_modified_dontaudits(self): """MLSvsStandardDiff: no modified dontaudit rules.""" self.assertFalse(self.diff.modified_dontaudits) def test_added_type_transitions(self): """MLSvsStandardDiff: no added type_transition rules.""" self.assertFalse(self.diff.added_type_transitions) def test_removed_type_transitions(self): """MLSvsStandardDiff: no removed type_transition rules.""" self.assertFalse(self.diff.removed_type_transitions) def test_modified_type_transitions(self): """MLSvsStandardDiff: no modified type_transition rules.""" self.assertFalse(self.diff.modified_type_transitions) def test_added_type_changes(self): """MLSvsStandardDiff: no added type_change rules.""" self.assertFalse(self.diff.added_type_changes) def test_removed_type_changes(self): """MLSvsStandardDiff: no removed type_change rules.""" self.assertFalse(self.diff.removed_type_changes) def test_modified_type_changes(self): """MLSvsStandardDiff: no modified type_change rules.""" self.assertFalse(self.diff.modified_type_changes) def test_added_type_members(self): """MLSvsStandardDiff: no added type_member rules.""" self.assertFalse(self.diff.added_type_members) def test_removed_type_members(self): """MLSvsStandardDiff: no removed type_member rules.""" self.assertFalse(self.diff.removed_type_members) def test_modified_type_members(self): """MLSvsStandardDiff: no modified type_member rules.""" self.assertFalse(self.diff.modified_type_members) def test_added_range_transitions(self): """MLSvsStandardDiff: no added range_transition rules.""" self.assertFalse(self.diff.added_range_transitions) def test_removed_range_transitions(self): """MLSvsStandardDiff: all range_transition rules removed.""" self.assertEqual(self.diff.left_policy.range_transition_count, len(self.diff.removed_range_transitions)) def test_modified_range_transitions(self): """MLSvsStandardDiff: no modified range_transition rules.""" self.assertFalse(self.diff.modified_range_transitions) def test_added_role_allows(self): """MLSvsStandardDiff: no added role_allow rules.""" self.assertFalse(self.diff.added_role_allows) def test_removed_role_allows(self): """MLSvsStandardDiff: no removed role_allow rules.""" self.assertFalse(self.diff.removed_role_allows) def test_added_role_transitions(self): """MLSvsStandardDiff: no added role_transition rules.""" self.assertFalse(self.diff.added_role_transitions) def test_removed_role_transitions(self): """MLSvsStandardDiff: no removed role_transition rules.""" self.assertFalse(self.diff.removed_role_transitions) def test_modified_role_transitions(self): """MLSvsStandardDiff: no modified role_transition rules.""" self.assertFalse(self.diff.modified_role_transitions) def test_added_users(self): """MLSvsStandardDiff: no added users.""" self.assertFalse(self.diff.added_users) def test_removed_users(self): """MLSvsStandardDiff: no removed users.""" self.assertFalse(self.diff.removed_users) def test_modified_users(self): """MLSvsStandardDiff: all users modified.""" self.assertEqual(self.diff.left_policy.user_count, len(self.diff.modified_users)) def test_added_type_attributes(self): """MLSvsStandardDiff: no added type attribute.""" self.assertFalse(self.diff.added_type_attributes) def test_removed_type_attributes(self): """MLSvsStandardDiff: no removed type attributes.""" self.assertFalse(self.diff.removed_type_attributes) def test_modified_type_attributes(self): """MLSvsStandardDiff: no modified type attributes.""" self.assertFalse(self.diff.modified_type_attributes) def test_added_booleans(self): """MLSvsStandardDiff: no added booleans.""" self.assertFalse(self.diff.added_booleans) def test_removed_booleans(self): """MLSvsStandardDiff: no removed booleans.""" self.assertFalse(self.diff.removed_booleans) def test_modified_booleans(self): """MLSvsStandardDiff: no modified booleans.""" self.assertFalse(self.diff.modified_booleans) def test_added_categories(self): """MLSvsStandardDiff: no added categories.""" self.assertFalse(self.diff.added_categories) def test_removed_categories(self): """MLSvsStandardDiff: all categories removed.""" self.assertEqual(self.diff.left_policy.category_count, len(self.diff.removed_categories)) def test_modified_categories(self): """MLSvsStandardDiff: no modified categories.""" self.assertFalse(self.diff.modified_categories) def test_added_sensitivities(self): """MLSvsStandardDiff: no added sensitivities.""" self.assertFalse(self.diff.added_sensitivities) def test_removed_sensitivities(self): """MLSvsStandardDiff: all sensitivities removed.""" self.assertEqual(self.diff.left_policy.level_count, len(self.diff.removed_sensitivities)) def test_modified_sensitivities(self): """MLSvsStandardDiff: no modified sensitivities.""" self.assertFalse(self.diff.modified_sensitivities) def test_added_initialsids(self): """MLSvsStandardDiff: no added initialsids.""" self.assertFalse(self.diff.added_initialsids) def test_removed_initialsids(self): """MLSvsStandardDiff: no removed initialsids.""" self.assertFalse(self.diff.removed_initialsids) def test_modified_initialsids(self): """MLSvsStandardDiff: all initialsids modified.""" self.assertEqual(self.diff.left_policy.initialsids_count, len(self.diff.modified_initialsids)) def test_added_fs_uses(self): """MLSvsStandardDiff: no added fs_uses.""" self.assertFalse(self.diff.added_fs_uses) def test_removed_fs_uses(self): """MLSvsStandardDiff: no removed fs_uses.""" self.assertFalse(self.diff.removed_fs_uses) def test_modified_fs_uses(self): """MLSvsStandardDiff: all fs_uses modified.""" self.assertEqual(self.diff.left_policy.fs_use_count, len(self.diff.modified_fs_uses)) def test_added_genfscons(self): """MLSvsStandardDiff: no added genfscons.""" self.assertFalse(self.diff.added_genfscons) def test_removed_genfscons(self): """MLSvsStandardDiff: no removed genfscons.""" self.assertFalse(self.diff.removed_genfscons) def test_modified_genfscons(self): """MLSvsStandardDiff: all genfscons modified.""" self.assertEqual(self.diff.left_policy.genfscon_count, len(self.diff.modified_genfscons)) def test_added_levels(self): """MLSvsStandardDiff: no added levels.""" self.assertFalse(self.diff.added_levels) def test_removed_levels(self): """MLSvsStandardDiff: all levels removed.""" self.assertEqual(self.diff.left_policy.level_count, len(self.diff.removed_levels)) def test_modified_levels(self): """MLSvsStandardDiff: no modified levels.""" self.assertFalse(self.diff.modified_levels) def test_added_netifcons(self): """MLSvsStandardDiff: no added netifcons.""" self.assertFalse(self.diff.added_netifcons) def test_removed_netifcons(self): """MLSvsStandardDiff: no removed netifcons.""" self.assertFalse(self.diff.removed_netifcons) def test_modified_netifcons(self): """MLSvsStandardDiff: all netifcons modified.""" self.assertEqual(self.diff.left_policy.netifcon_count, len(self.diff.modified_netifcons)) def test_added_nodecons(self): """MLSvsStandardDiff: no added nodecons.""" self.assertFalse(self.diff.added_nodecons) def test_removed_nodecons(self): """MLSvsStandardDiff: no removed nodecons.""" self.assertFalse(self.diff.removed_nodecons) def test_modified_nodecons(self): """MLSvsStandardDiff: all nodecons modified.""" self.assertEqual(self.diff.left_policy.nodecon_count, len(self.diff.modified_nodecons)) def test_added_polcaps(self): """MLSvsStandardDiff: no added polcaps.""" self.assertFalse(self.diff.added_polcaps) def test_removed_polcaps(self): """MLSvsStandardDiff: no removed polcaps.""" self.assertFalse(self.diff.removed_polcaps) def test_added_portcons(self): """MLSvsStandardDiff: no added portcons.""" self.assertFalse(self.diff.added_portcons) def test_removed_portcons(self): """MLSvsStandardDiff: no removed portcons.""" self.assertFalse(self.diff.removed_portcons) def test_modified_portcons(self): """MLSvsStandardDiff: all portcons modified.""" self.assertEqual(self.diff.left_policy.portcon_count, len(self.diff.modified_portcons)) def test_modified_properties(self): """MLSvsStandardDiff: MLS property modified only.""" self.assertEqual(1, len(self.diff.modified_properties)) name, added, removed = self.diff.modified_properties[0] self.assertEqual("MLS", name) self.assertIs(False, added) self.assertIs(True, removed) def test_added_defaults(self): """MLSvsStandardDiff: no added defaults.""" self.assertFalse(self.diff.added_defaults) def test_removed_defaults(self): """MLSvsStandardDiff: all default_range removed.""" self.assertEqual( sum(1 for d in self.diff.left_policy.defaults() if d.ruletype == DRT.default_range), len(self.diff.removed_defaults)) def test_modified_defaults(self): """MLSvsStandardDiff: no defaults modified.""" self.assertFalse(self.diff.modified_defaults) def test_added_constraints(self): """MLSvsStandardDiff: no added constraints.""" self.assertFalse(self.diff.added_constrains) def test_removed_constraints(self): """MLSvsStandardDiff: no removed constraints.""" self.assertFalse(self.diff.removed_constrains) def test_added_validatetrans(self): """MLSvsStandardDiff: no added validatetrans.""" self.assertFalse(self.diff.added_validatetrans) def test_removed_validatetrans(self): """MLSvsStandardDiff: no removed validatetrans.""" self.assertFalse(self.diff.removed_validatetrans) def test_added_mlsconstraints(self): """MLSvsStandardDiff: no added mlsconstraints.""" self.assertFalse(self.diff.added_mlsconstrains) def test_removed_mlsconstraints(self): """MLSvsStandardDiff: all mlsconstraints removed.""" self.assertEqual( sum(1 for m in self.diff.left_policy.constraints() if m.ruletype == CRT.mlsconstrain), len(self.diff.removed_mlsconstrains)) def test_added_mlsvalidatetrans(self): """MLSvsStandardDiff: no added mlsvalidatetrans.""" self.assertFalse(self.diff.added_mlsvalidatetrans) def test_removed_mlsvalidatetrans(self): """MLSvsStandardDiff: all mlsvalidatetrans removed.""" self.assertEqual( sum(1 for m in self.diff.left_policy.constraints() if m.ruletype == CRT.mlsvalidatetrans), len(self.diff.removed_mlsvalidatetrans)) def test_added_typebounds(self): """MLSvsStandardDiff: no added typebounds.""" self.assertFalse(self.diff.added_typebounds) def test_removed_typebounds(self): """MLSvsStandardDiff: no removed typebounds.""" self.assertFalse(self.diff.removed_typebounds) def test_modified_typebounds(self): """MLSvsStandardDiff: no modified typebounds.""" self.assertFalse(self.diff.modified_typebounds) def test_added_allowxperms(self): """NoDiff: no added allowxperm rules.""" self.assertFalse(self.diff.added_allowxperms) def test_removed_allowxperms(self): """NoDiff: no removed allowxperm rules.""" self.assertFalse(self.diff.removed_allowxperms) def test_modified_allowxperms(self): """NoDiff: no modified allowxperm rules.""" self.assertFalse(self.diff.modified_allowxperms) def test_added_auditallowxperms(self): """NoDiff: no added auditallowxperm rules.""" self.assertFalse(self.diff.added_auditallowxperms) def test_removed_auditallowxperms(self): """NoDiff: no removed auditallowxperm rules.""" self.assertFalse(self.diff.removed_auditallowxperms) def test_modified_auditallowxperms(self): """NoDiff: no modified auditallowxperm rules.""" self.assertFalse(self.diff.modified_auditallowxperms) def test_added_neverallowxperms(self): """NoDiff: no added neverallowxperm rules.""" self.assertFalse(self.diff.added_neverallowxperms) def test_removed_neverallowxperms(self): """NoDiff: no removed neverallowxperm rules.""" self.assertFalse(self.diff.removed_neverallowxperms) def test_modified_neverallowxperms(self): """NoDiff: no modified neverallowxperm rules.""" self.assertFalse(self.diff.modified_neverallowxperms) def test_added_dontauditxperms(self): """NoDiff: no added dontauditxperm rules.""" self.assertFalse(self.diff.added_dontauditxperms) def test_removed_dontauditxperms(self): """NoDiff: no removed dontauditxperm rules.""" self.assertFalse(self.diff.removed_dontauditxperms) def test_modified_dontauditxperms(self): """NoDiff: no modified dontauditxperm rules.""" self.assertFalse(self.diff.modified_dontauditxperms) def test_added_ibpkeycons(self): """NoDiff: no added ibpkeycon rules.""" self.assertFalse(self.diff.added_ibpkeycons) def test_removed_ibpkeycons(self): """NoDiff: no removed ibpkeycon rules.""" self.assertFalse(self.diff.removed_ibpkeycons) def test_modified_ibpkeycons(self): """NoDiff: no modified ibpkeycon rules.""" self.assertEqual(self.diff.left_policy.ibpkeycon_count, len(self.diff.modified_ibpkeycons)) def test_added_ibendportcons(self): """NoDiff: no added ibendportcon rules.""" self.assertFalse(self.diff.added_ibendportcons) def test_removed_ibendportcons(self): """NoDiff: no removed ibendportcon rules.""" self.assertFalse(self.diff.removed_ibendportcons) def test_modified_ibendportcons(self): """NoDiff: no modified ibendportcon rules.""" self.assertEqual(self.diff.left_policy.ibendportcon_count, len(self.diff.modified_ibendportcons)) class PolicyDifferenceTestRedundant(unittest.TestCase): """ Policy difference test with redundant rules. There should be no policy differences. """ @classmethod def setUpClass(cls): cls.p_left = compile_policy("tests/diff_left.conf") cls.p_right = compile_policy("tests/diff_left_redundant.conf") cls.diff = PolicyDifference(cls.p_left, cls.p_right) @classmethod def tearDownClass(cls): os.unlink(cls.p_left.path) os.unlink(cls.p_right.path) def test_added_allows(self): """Redundant: no added allow rules.""" self.assertFalse(self.diff.added_allows) def test_removed_allows(self): """Redundant: no removed allow rules.""" self.assertFalse(self.diff.removed_allows) def test_modified_allows(self): """Redundant: no modified allow rules.""" self.assertFalse(self.diff.modified_allows) setools-4.4.0/tests/diff_left.conf000066400000000000000000000641441402045477700171650ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid unlabeled sid fs sid file common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: # removed: default_role infoflow3 source; default_range infoflow3 target high; # modified: default_type infoflow4 source; default_range infoflow4 source low; # modified range: default_range infoflow5 target low; # modified both default_range infoflow6 source high; sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint # removed mls constraint mlsconstrain infoflow4 hi_w ((l1 domby l2 and h1 domby h2) or (t1 == mls_exempt)); # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 dom h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans # removed mls validatetrans mlsvalidatetrans infoflow4 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 dom l2 and h1 dom h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; attribute redundant_rule_attr; type redundant_rule_source_1, redundant_rule_attr; type redundant_rule_source_2, redundant_rule_attr; type redundant_rule_target_1; type redundant_rule_target_2; bool redundant_rule_bool true; allow redundant_rule_attr redundant_rule_target_1:infoflow low_w; allow redundant_rule_attr redundant_rule_target_2:infoflow med_w; if (redundant_rule_bool) { allow redundant_rule_source_2 redundant_rule_target_2:infoflow hi_w; } # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; range_transition rt_removed_rule_source rt_removed_rule_target:infoflow s1; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_matched_source system:infoflow s2:c0 - s3:c0.c2; range_transition removed_type system:infoflow4 s1; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #range_transition rt_move_to_bool system:infoflow3 s0; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #range_transition rt_move_from_bool system:infoflow4 s0; #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #range_transition system rt_switch_block:infoflow6 s0; #} else { #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_A_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c3; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid unlabeled system:system:system:s0 sid fs removed_user:system:system:s0 sid file system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 121.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff01:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # removed nodecons nodecon 122.0.0.0 255.0.0.0 removed_user:object_r:system:s0 nodecon ff02:: ffff:ffff:ffff:fffc:: removed_user:object_r:system:s0 # modified nodecons nodecon 123.0.0.0 255.0.0.0 modified_change_level:object_r:system:s2:c1 nodecon ff03:: ffff:ffff:ffff:fffc:: modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 125.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff05:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # matched ibpkeycons ibpkeycon eeee:: 0x1-0xdddd system:system:system:s0 ibpkeycon dddd:: 0xeeee system:system:system:s0 # added ibpkeycons # removed ibpkeycons ibpkeycon feee:: 0xaaaa-0xbbbb system:system:system:s0 ibpkeycon dccc:: 0xc system:system:system:s0 # modified ibpkeycons ibpkeycon aaaa:: 0xcccc-0xdddd modified_change_level:object_r:system:s2:c1 ibpkeycon bbbb:: 0xf modified_change_level:object_r:system:s2:c0,c1 # matched ibendportcons ibendportcon match 1 system:system:system:s0 # added ibendportcons # removed ibendportcons ibendportcon removed 7 system:system:system:s0 # modified ibendportcons ibendportcon modified 13 modified_change_level:object_r:system:s2:c0,c1 setools-4.4.0/tests/diff_left_redundant.conf000066400000000000000000000642721402045477700212330ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid unlabeled sid fs sid file common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: # removed: default_role infoflow3 source; default_range infoflow3 target high; # modified: default_type infoflow4 source; default_range infoflow4 source low; # modified range: default_range infoflow5 target low; # modified both default_range infoflow6 source high; sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint # removed mls constraint mlsconstrain infoflow4 hi_w ((l1 domby l2 and h1 domby h2) or (t1 == mls_exempt)); # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 dom h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans # removed mls validatetrans mlsvalidatetrans infoflow4 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 dom l2 and h1 dom h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; range_transition rt_removed_rule_source rt_removed_rule_target:infoflow s1; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_matched_source system:infoflow s2:c0 - s3:c0.c2; range_transition removed_type system:infoflow4 s1; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #range_transition rt_move_to_bool system:infoflow3 s0; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #range_transition rt_move_from_bool system:infoflow4 s0; #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #range_transition system rt_switch_block:infoflow6 s0; #} else { #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_A_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; attribute redundant_rule_attr; type redundant_rule_source_1, redundant_rule_attr; type redundant_rule_source_2, redundant_rule_attr; type redundant_rule_target_1; type redundant_rule_target_2; bool redundant_rule_bool true; allow redundant_rule_attr redundant_rule_target_1:infoflow low_w; allow redundant_rule_attr redundant_rule_target_2:infoflow med_w; if (redundant_rule_bool) { allow redundant_rule_source_1 redundant_rule_target_1:infoflow low_w; allow redundant_rule_source_2 redundant_rule_target_2:infoflow { med_w hi_w }; } ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c3; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid unlabeled system:system:system:s0 sid fs removed_user:system:system:s0 sid file system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 121.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff01:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # removed nodecons nodecon 122.0.0.0 255.0.0.0 removed_user:object_r:system:s0 nodecon ff02:: ffff:ffff:ffff:fffc:: removed_user:object_r:system:s0 # modified nodecons nodecon 123.0.0.0 255.0.0.0 modified_change_level:object_r:system:s2:c1 nodecon ff03:: ffff:ffff:ffff:fffc:: modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 125.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff05:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # matched ibpkeycons ibpkeycon eeee:: 0x1-0xdddd system:system:system:s0 ibpkeycon dddd:: 0xeeee system:system:system:s0 # added ibpkeycons # removed ibpkeycons ibpkeycon feee:: 0xaaaa-0xbbbb system:system:system:s0 ibpkeycon dccc:: 0xc system:system:system:s0 # modified ibpkeycons ibpkeycon aaaa:: 0xcccc-0xdddd modified_change_level:object_r:system:s2:c1 ibpkeycon bbbb:: 0xf modified_change_level:object_r:system:s2:c0,c1 # matched ibendportcons ibendportcon match 1 system:system:system:s0 # added ibendportcons # removed ibendportcons ibendportcon removed 7 system:system:system:s0 # modified ibendportcons ibendportcon modified 13 modified_change_level:object_r:system:s2:c0,c1 setools-4.4.0/tests/diff_left_standard.conf000066400000000000000000000571301402045477700210420ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid unlabeled sid fs sid file common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow class modified_change_common inherits removed_common # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; # added: # removed: default_role infoflow3 source; # modified: default_type infoflow4 source; attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; type rt_matched_source; type rt_matched_target; type rt_removed_rule_source; type rt_removed_rule_target; type rt_added_rule_source; type rt_added_rule_target; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #} else { #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; attribute redundant_rule_attr; type redundant_rule_source_1, redundant_rule_attr; type redundant_rule_source_2, redundant_rule_attr; type redundant_rule_target_1; type redundant_rule_target_2; bool redundant_rule_bool true; allow redundant_rule_attr redundant_rule_target_1:infoflow low_w; allow redundant_rule_attr redundant_rule_target_2:infoflow med_w; if (redundant_rule_bool) { allow redundant_rule_source_2 redundant_rule_target_2:infoflow hi_w; } ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system; user removed_user roles system; user modified_add_role roles system; user modified_remove_role roles { system removed_role }; user modified_change_level roles system; user modified_change_range roles system; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system sid security system:system:system sid unlabeled system:system:system sid fs removed_user:system:system sid file system:system:system #fs_use fs_use_trans devpts system:object_r:system; fs_use_xattr ext3 system:object_r:system; fs_use_task pipefs system:object_r:system; fs_use_task removed_fsuse system:object_r:system; fs_use_trans modified_fsuse removed_user:object_r:system; #genfscon genfscon proc / system:object_r:system genfscon proc /sys system:object_r:system genfscon selinuxfs / system:object_r:system genfscon removed_genfs / system:object_r:system genfscon change_path /old system:object_r:system genfscon modified_genfs / -s removed_user:object_r:system # matched portcons portcon tcp 80 system:object_r:system portcon udp 80 system:object_r:system portcon udp 30-40 system:object_r:system # removed portcons portcon udp 1024 system:object_r:system portcon tcp 1024-1026 system:object_r:system # modified portcons portcon udp 3024 removed_user:object_r:system portcon tcp 3024-3026 removed_user:object_r:system netifcon eth0 system:object_r:system system:object_r:system netifcon removed_netif system:object_r:system system:object_r:system netifcon mod_ctx_netif removed_user:object_r:system system:object_r:system netifcon mod_pkt_netif system:object_r:system removed_user:object_r:system netifcon mod_both_netif removed_user:object_r:system removed_user:object_r:system # matched nodecons nodecon 121.0.0.0 255.0.0.0 system:object_r:system nodecon ff01:: ffff:ffff:ffff:fffc:: system:object_r:system # removed nodecons nodecon 122.0.0.0 255.0.0.0 removed_user:object_r:system nodecon ff02:: ffff:ffff:ffff:fffc:: removed_user:object_r:system # modified nodecons nodecon 123.0.0.0 255.0.0.0 modified_change_level:object_r:system nodecon ff03:: ffff:ffff:ffff:fffc:: modified_change_level:object_r:system # change netmask (add/remove) nodecon 125.0.0.0 255.0.0.0 system:object_r:system nodecon ff05:: ffff:ffff:ffff:fffc:: system:object_r:system # matched ibpkeycons ibpkeycon eeee:: 0x1-0xdddd system:system:system ibpkeycon dddd:: 0xeeee system:system:system # added ibpkeycons # removed ibpkeycons ibpkeycon feee:: 0xaaaa-0xbbbb system:system:system ibpkeycon dccc:: 0xc system:system:system # modified ibpkeycons ibpkeycon aaaa:: 0xcccc-0xdddd modified_change_level:object_r:system ibpkeycon bbbb:: 0xf modified_change_level:object_r:system # matched ibendportcons ibendportcon match 1 system:system:system # added ibendportcons # removed ibendportcons ibendportcon removed 7 system:system:system # modified ibendportcons ibendportcon modified 13 modified_change_level:object_r:system setools-4.4.0/tests/diff_right.conf000066400000000000000000000667171402045477700173600ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 class added_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid unlabeled sid fs sid file sid file_labels common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common added_common { new_com } common modified_remove_perm { same_perm } common modified_add_perm { matched_perm added_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class added_class { new_class_perm } class modified_add_perm { same_perm added_perm } class modified_remove_perm { same_perm } class modified_change_common inherits added_common class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: default_user infoflow2 target; default_range infoflow2 source low; # removed: # modified: default_type infoflow4 target; default_range infoflow4 target low; # modified range: default_range infoflow5 target high; # modified both default_range infoflow6 target low; sensitivity s0 alias { al1 }; sensitivity s1 alias { al3 al4 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s46; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 } category c0 alias { spam }; category c1 alias { foo bar }; category c2; category c3; category c4; category c6; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1,c3; level s41:c0.c3; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s46:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint mlsconstrain infoflow3 null ((l1 domby l2 and h1 domby h2) or (t1 != mls_exempt)); # removed mls constraint # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 incomp h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans mlsvalidatetrans infoflow3 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # removed mls validatetrans # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 incomp l2 and h1 domby h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute added_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type added_type; type modified_remove_attr; type modified_remove_alias; type modified_remove_permissive; type modified_add_attr, an_attr; type modified_add_alias alias an_alias; type modified_add_permissive; permissive modified_add_permissive; role added_role; role modified_add_type; role modified_add_type types { system }; role modified_remove_type; # booleans bool same_bool true; bool added_bool true; bool modified_bool true; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; type added_rule_source; type added_rule_target; allow added_rule_source added_rule_target:infoflow med_w; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow { hi_r hi_w }; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow low_w; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; allow added_type self:infoflow2 med_w; type move_to_bool; bool move_to_bool_b false; if (move_to_bool_b) { allow move_to_bool self:infoflow4 hi_w; } type move_from_bool; bool move_from_bool_b false; allow move_from_bool self:infoflow4 hi_r; type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; } else { allow system switch_block:infoflow6 hi_r; allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr_A_t self:infoflow2 super_w; allow match_rule_by_attr_B_t self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_a union_perm_b:infoflow hi_w; allow union_perm_c union_perm_target:infoflow med_w; allow union_perm_source union_perm_target:infoflow low_w; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; type aa_added_rule_source; type aa_added_rule_target; auditallow aa_added_rule_source aa_added_rule_target:infoflow med_w; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow { hi_r hi_w }; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow low_w; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; auditallow added_type self:infoflow7 super_none; type aa_move_to_bool; bool aa_move_to_bool_b false; if (aa_move_to_bool_b) { auditallow aa_move_to_bool self:infoflow4 hi_w; } type aa_move_from_bool; bool aa_move_from_bool_b false; auditallow aa_move_from_bool self:infoflow4 hi_r; type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; } else { auditallow system aa_switch_block:infoflow6 hi_r; auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr_A_t self:infoflow2 super_w; auditallow aa_match_rule_by_attr_B_t self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_a aa_union_perm_b:infoflow hi_w; auditallow aa_union_perm_c aa_union_perm_target:infoflow med_w; auditallow aa_union_perm_source aa_union_perm_target:infoflow low_w; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; type da_added_rule_source; type da_added_rule_target; dontaudit da_added_rule_source da_added_rule_target:infoflow med_w; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow { hi_r hi_w }; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow low_w; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; dontaudit added_type self:infoflow7 super_none; type da_move_to_bool; bool da_move_to_bool_b false; if (da_move_to_bool_b) { dontaudit da_move_to_bool self:infoflow4 hi_w; } type da_move_from_bool; bool da_move_from_bool_b false; dontaudit da_move_from_bool self:infoflow4 hi_r; type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; } else { dontaudit system da_switch_block:infoflow6 hi_r; dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr_A_t self:infoflow2 super_w; dontaudit da_match_rule_by_attr_B_t self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_a da_union_perm_b:infoflow hi_w; dontaudit da_union_perm_c da_union_perm_target:infoflow med_w; dontaudit da_union_perm_source da_union_perm_target:infoflow low_w; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; type na_added_rule_source; type na_added_rule_target; neverallow na_added_rule_source na_added_rule_target:infoflow med_w; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow { hi_r hi_w }; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow low_w; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_r }; neverallow added_type self:added_class new_class_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr_A_t self:infoflow2 super_w; neverallow na_match_rule_by_attr_B_t self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_a na_union_perm_b:infoflow hi_w; neverallow na_union_perm_c na_union_perm_target:infoflow med_w; neverallow na_union_perm_source na_union_perm_target:infoflow low_w; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type tt_added_rule_source; type tt_added_rule_target; type_transition tt_added_rule_source tt_added_rule_target:infoflow system; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_new_type; type_transition added_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; if (tt_move_to_bool_b) { type_transition tt_move_to_bool system:infoflow3 system; } type tt_move_from_bool; bool tt_move_from_bool_b false; type_transition tt_move_from_bool system:infoflow4 system; type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; } else { type_transition system tt_switch_block:infoflow6 system; type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type tc_added_rule_source; type tc_added_rule_target; type_change tc_added_rule_source tc_added_rule_target:infoflow system; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_new_type; type_change added_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; if (tc_move_to_bool_b) { type_change tc_move_to_bool system:infoflow3 system; } type tc_move_from_bool; bool tc_move_from_bool_b false; type_change tc_move_from_bool system:infoflow4 system; type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; } else { type_change system tc_switch_block:infoflow6 system; type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type tm_added_rule_source; type tm_added_rule_target; type_member tm_added_rule_source tm_added_rule_target:infoflow system; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_new_type; type_member added_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; if (tm_move_to_bool_b) { type_member tm_move_to_bool system:infoflow3 system; } type tm_move_from_bool; bool tm_move_from_bool_b false; type_member tm_move_from_bool system:infoflow4 system; type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; } else { type_member system tm_switch_block:infoflow6 system; type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_added_rule_source rt_added_rule_target:infoflow s3; range_transition rt_matched_source system:infoflow s0:c0,c4 - s1:c0.c2,c4; range_transition added_type system:infoflow4 s3; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #if (rt_move_to_bool_b) { #range_transition rt_move_to_bool system:infoflow3 s0; #} #type rt_move_from_bool; #bool rt_move_from_bool_b false; #range_transition rt_move_from_bool system:infoflow4 s0; #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #} else { #range_transition system rt_switch_block:infoflow6 s0; #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_B_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow added_rule_source_r added_rule_target_r; allow added_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition role_tr_added_rule_source role_tr_added_rule_target:infoflow6 system; role_transition added_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_new_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; type ax_added_rule_source; type ax_added_rule_target; allowxperm ax_added_rule_source ax_added_rule_target:infoflow ioctl 0x0002; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; allowxperm added_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; allowxperm ax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_a ax_union_perm_b:infoflow ioctl 0x1; allowxperm ax_union_perm_c ax_union_perm_target:infoflow ioctl 0x2; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl 0x3; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; type aax_added_rule_source; type aax_added_rule_target; auditallowxperm aax_added_rule_source aax_added_rule_target:infoflow ioctl 0x0002; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; auditallowxperm added_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; auditallowxperm aax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_a aax_union_perm_b:infoflow ioctl 0x1; auditallowxperm aax_union_perm_c aax_union_perm_target:infoflow ioctl 0x2; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl 0x3; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; type nax_added_rule_source; type nax_added_rule_target; neverallowxperm nax_added_rule_source nax_added_rule_target:infoflow ioctl 0x0002; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; neverallowxperm added_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; neverallowxperm nax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_a nax_union_perm_b:infoflow ioctl 0x1; neverallowxperm nax_union_perm_c nax_union_perm_target:infoflow ioctl 0x2; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl 0x3; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; type dax_added_rule_source; type dax_added_rule_target; dontauditxperm dax_added_rule_source dax_added_rule_target:infoflow ioctl 0x0002; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl { 0x0004 0x000f }; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl 0x0005; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0006 0x0008 }; dontauditxperm added_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr_A_t self:infoflow2 ioctl 0x000a; dontauditxperm dax_match_rule_by_attr_B_t self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_a dax_union_perm_b:infoflow ioctl 0x1; dontauditxperm dax_union_perm_c dax_union_perm_target:infoflow ioctl 0x2; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl 0x3; attribute redundant_rule_attr; type redundant_rule_source_1, redundant_rule_attr; type redundant_rule_source_2, redundant_rule_attr; type redundant_rule_target_1; type redundant_rule_target_2; bool redundant_rule_bool true; allow redundant_rule_attr redundant_rule_target_1:infoflow low_w; allow redundant_rule_attr redundant_rule_target_2:infoflow med_w; if (redundant_rule_bool) { allow redundant_rule_source_2 redundant_rule_target_2:infoflow hi_w; } ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; # added typebounds type added_parent; type added_child; typebounds added_parent added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_added mod_child; # policycaps policycap open_perms; policycap always_check_network; #users user system roles system level s0 range s0; user added_user roles system level s1 range s1; user modified_add_role roles { system added_role } level s2 range s2; user modified_remove_role roles system level s2 range s2; user modified_change_level roles system level s2:c1 range s2:c1 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c4; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint constrain infoflow3 null (u1 != u2); # removed constraint # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 != system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans validatetrans infoflow3 (t1 == t2 or t3 == system); # removed validatetrans # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 != u2 and r1 == r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid unlabeled system:system:system:s0 sid fs system:system:system:s0 sid file system:system:system:s0 sid file_labels added_user:system:system:s1 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_xattr added_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse added_user:object_r:system:s1; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon added_genfs / added_user:object_r:system:s0 genfscon change_path /new system:object_r:system:s0 genfscon modified_genfs / -s added_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # added portcons portcon udp 2024 system:object_r:system:s0 portcon tcp 2024-2026 system:object_r:system:s0 # modified portcons portcon udp 3024 added_user:object_r:system:s1 portcon tcp 3024-3026 added_user:object_r:system:s1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon added_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif added_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 added_user:object_r:system:s0 netifcon mod_both_netif added_user:object_r:system:s0 added_user:object_r:system:s0 # matched nodecons nodecon 121.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff01:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # added nodecons nodecon 124.0.0.0 255.0.0.0 added_user:object_r:system:s0 nodecon ff04:: ffff:ffff:ffff:fffc:: added_user:object_r:system:s0 # modified nodecons nodecon 123.0.0.0 255.0.0.0 modified_change_level:object_r:system:s2:c0 nodecon ff03:: ffff:ffff:ffff:fffc:: modified_change_level:object_r:system:s2:c1 # change netmask (add/remove) nodecon 125.0.0.0 255.255.0.0 system:object_r:system:s0 nodecon ff05:: ffff:ffff:ffff:fff0:: system:object_r:system:s0 # matched ibpkeycons ibpkeycon eeee:: 0x1-0xdddd system:system:system:s0 ibpkeycon dddd:: 0xeeee system:system:system:s0 # added ibpkeycons ibpkeycon dead:: 0xbeef-0xdead system:system:system:s0 ibpkeycon beef:: 0xe system:system:system:s0 # removed ibpkeycons # modified ibpkeycons ibpkeycon aaaa:: 0xcccc-0xdddd modified_change_level:object_r:system:s2:c0 ibpkeycon bbbb:: 0xf modified_change_level:object_r:system:s2:c1 # matched ibendportcons ibendportcon match 1 system:system:system:s0 # added ibendportcons ibendportcon add 23 system:system:system:s0 # removed ibendportcons # modified ibendportcons ibendportcon modified 13 modified_change_level:object_r:system:s2 setools-4.4.0/tests/diff_right_rmisid.conf000066400000000000000000000626101402045477700207130ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid unlabeled sid fs common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow # matching defaults: default_user infoflow source; default_role infoflow source; default_type infoflow source; default_range infoflow source low; # added: # removed: default_role infoflow3 source; default_range infoflow3 target high; # modified: default_type infoflow4 source; default_range infoflow4 source low; # modified range: default_range infoflow5 target low; # modified both default_range infoflow6 source high; sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; # matching mls constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); # added mls constraint # removed mls constraint mlsconstrain infoflow4 hi_w ((l1 domby l2 and h1 domby h2) or (t1 == mls_exempt)); # remove/add mls constraint (expression change) mlsconstrain infoflow5 hi_r ((l1 domby l2 and h1 dom h2) or (t1 == mls_exempt)); # matching mls validatetrans mlsvalidatetrans infoflow (h1 == h2 or t3 == system); # added mls validatetrans # removed mls validatetrans mlsvalidatetrans infoflow4 ((l1 == l2 and h1 == h2) or t3 == mls_exempt); # remove/add mls validatetrans (expression change) mlsvalidatetrans infoflow5 ((l1 dom l2 and h1 dom h2) or (t3 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; # Allow rule differences type matched_source; type matched_target; allow matched_source matched_target:infoflow hi_w; type removed_rule_source; type removed_rule_target; allow removed_rule_source removed_rule_target:infoflow hi_r; type added_rule_source; type added_rule_target; type modified_rule_add_perms; allow modified_rule_add_perms self:infoflow hi_r; type modified_rule_remove_perms; allow modified_rule_remove_perms self:infoflow { low_r low_w }; type modified_rule_add_remove_perms; allow modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; allow removed_type self:infoflow3 null; type move_to_bool; bool move_to_bool_b false; allow move_to_bool self:infoflow4 hi_w; type move_from_bool; bool move_from_bool_b false; if (move_from_bool_b) { allow move_from_bool self:infoflow4 hi_r; } type switch_block; bool switch_block_b false; if (switch_block_b) { allow system switch_block:infoflow5 hi_r; allow system switch_block:infoflow6 hi_r; } else { allow system switch_block:infoflow7 hi_r; } attribute match_rule_by_attr; type match_rule_by_attr_A_t, match_rule_by_attr; type match_rule_by_attr_B_t, match_rule_by_attr; allow match_rule_by_attr self:infoflow2 super_w; attribute union_perm_a; attribute union_perm_b; attribute union_perm_c; type union_perm_source, union_perm_a, union_perm_c; type union_perm_target, union_perm_b; allow union_perm_source union_perm_target:infoflow { hi_w med_w low_w }; # Auditallow rule differences type aa_matched_source; type aa_matched_target; auditallow aa_matched_source aa_matched_target:infoflow hi_w; type aa_removed_rule_source; type aa_removed_rule_target; auditallow aa_removed_rule_source aa_removed_rule_target:infoflow hi_r; type aa_added_rule_source; type aa_added_rule_target; type aa_modified_rule_add_perms; auditallow aa_modified_rule_add_perms self:infoflow hi_r; type aa_modified_rule_remove_perms; auditallow aa_modified_rule_remove_perms self:infoflow { low_r low_w }; type aa_modified_rule_add_remove_perms; auditallow aa_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; auditallow removed_type self:infoflow7 super_unmapped; type aa_move_to_bool; bool aa_move_to_bool_b false; auditallow aa_move_to_bool self:infoflow4 hi_w; type aa_move_from_bool; bool aa_move_from_bool_b false; if (aa_move_from_bool_b) { auditallow aa_move_from_bool self:infoflow4 hi_r; } type aa_switch_block; bool aa_switch_block_b false; if (aa_switch_block_b) { auditallow system aa_switch_block:infoflow5 hi_r; auditallow system aa_switch_block:infoflow6 hi_r; } else { auditallow system aa_switch_block:infoflow7 hi_r; } attribute aa_match_rule_by_attr; type aa_match_rule_by_attr_A_t, aa_match_rule_by_attr; type aa_match_rule_by_attr_B_t, aa_match_rule_by_attr; auditallow aa_match_rule_by_attr self:infoflow2 super_w; attribute aa_union_perm_a; attribute aa_union_perm_b; attribute aa_union_perm_c; type aa_union_perm_source, aa_union_perm_a, aa_union_perm_c; type aa_union_perm_target, aa_union_perm_b; auditallow aa_union_perm_source aa_union_perm_target:infoflow { hi_w med_w low_w }; # Dontaudit rule differences type da_matched_source; type da_matched_target; dontaudit da_matched_source da_matched_target:infoflow hi_w; type da_removed_rule_source; type da_removed_rule_target; dontaudit da_removed_rule_source da_removed_rule_target:infoflow hi_r; type da_added_rule_source; type da_added_rule_target; type da_modified_rule_add_perms; dontaudit da_modified_rule_add_perms self:infoflow hi_r; type da_modified_rule_remove_perms; dontaudit da_modified_rule_remove_perms self:infoflow { low_r low_w }; type da_modified_rule_add_remove_perms; dontaudit da_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; dontaudit removed_type self:infoflow7 super_both; type da_move_to_bool; bool da_move_to_bool_b false; dontaudit da_move_to_bool self:infoflow4 hi_w; type da_move_from_bool; bool da_move_from_bool_b false; if (da_move_from_bool_b) { dontaudit da_move_from_bool self:infoflow4 hi_r; } type da_switch_block; bool da_switch_block_b false; if (da_switch_block_b) { dontaudit system da_switch_block:infoflow5 hi_r; dontaudit system da_switch_block:infoflow6 hi_r; } else { dontaudit system da_switch_block:infoflow7 hi_r; } attribute da_match_rule_by_attr; type da_match_rule_by_attr_A_t, da_match_rule_by_attr; type da_match_rule_by_attr_B_t, da_match_rule_by_attr; dontaudit da_match_rule_by_attr self:infoflow2 super_w; attribute da_union_perm_a; attribute da_union_perm_b; attribute da_union_perm_c; type da_union_perm_source, da_union_perm_a, da_union_perm_c; type da_union_perm_target, da_union_perm_b; dontaudit da_union_perm_source da_union_perm_target:infoflow { hi_w med_w low_w }; # Neverallow rule differences type na_matched_source; type na_matched_target; neverallow na_matched_source na_matched_target:infoflow hi_w; type na_removed_rule_source; type na_removed_rule_target; neverallow na_removed_rule_source na_removed_rule_target:infoflow hi_r; type na_added_rule_source; type na_added_rule_target; type na_modified_rule_add_perms; neverallow na_modified_rule_add_perms self:infoflow hi_r; type na_modified_rule_remove_perms; neverallow na_modified_rule_remove_perms self:infoflow { low_r low_w }; type na_modified_rule_add_remove_perms; neverallow na_modified_rule_add_remove_perms self:infoflow2 { low_w super_w }; neverallow removed_type self:removed_class null_perm; attribute na_match_rule_by_attr; type na_match_rule_by_attr_A_t, na_match_rule_by_attr; type na_match_rule_by_attr_B_t, na_match_rule_by_attr; neverallow na_match_rule_by_attr self:infoflow2 super_w; attribute na_union_perm_a; attribute na_union_perm_b; attribute na_union_perm_c; type na_union_perm_source, na_union_perm_a, na_union_perm_c; type na_union_perm_target, na_union_perm_b; neverallow na_union_perm_source na_union_perm_target:infoflow { hi_w med_w low_w }; # type_transition rule differences type tt_matched_source; type tt_matched_target; type_transition tt_matched_source tt_matched_target:infoflow system; type tt_removed_rule_source; type tt_removed_rule_target; type_transition tt_removed_rule_source tt_removed_rule_target:infoflow system; type tt_added_rule_source; type tt_added_rule_target; type tt_old_type; type tt_new_type; type_transition tt_matched_source system:infoflow tt_old_type; type_transition removed_type system:infoflow4 system; type tt_move_to_bool; bool tt_move_to_bool_b false; type_transition tt_move_to_bool system:infoflow3 system; type tt_move_from_bool; bool tt_move_from_bool_b false; if (tt_move_from_bool_b) { type_transition tt_move_from_bool system:infoflow4 system; } type tt_switch_block; bool tt_switch_block_b false; if (tt_switch_block_b) { type_transition system tt_switch_block:infoflow5 system; type_transition system tt_switch_block:infoflow6 system; } else { type_transition system tt_switch_block:infoflow7 system; } attribute tt_match_rule_by_attr; type tt_match_rule_by_attr_A_t, tt_match_rule_by_attr; type tt_match_rule_by_attr_B_t, tt_match_rule_by_attr; type_transition tt_match_rule_by_attr system:infoflow2 system; attribute tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_A_t, tt_unioned_perm_via_attr; type tt_unioned_perm_via_attr_B_t, tt_unioned_perm_via_attr; type_transition tt_unioned_perm_via_attr system:infoflow2 system; type_transition tt_unioned_perm_via_attr_A_t system:infoflow2 system; type_transition tt_unioned_perm_via_attr_B_t system:infoflow2 system; # type_change rule differences type tc_matched_source; type tc_matched_target; type_change tc_matched_source tc_matched_target:infoflow system; type tc_removed_rule_source; type tc_removed_rule_target; type_change tc_removed_rule_source tc_removed_rule_target:infoflow system; type tc_added_rule_source; type tc_added_rule_target; type tc_old_type; type tc_new_type; type_change tc_matched_source system:infoflow tc_old_type; type_change removed_type system:infoflow4 system; type tc_move_to_bool; bool tc_move_to_bool_b false; type_change tc_move_to_bool system:infoflow3 system; type tc_move_from_bool; bool tc_move_from_bool_b false; if (tc_move_from_bool_b) { type_change tc_move_from_bool system:infoflow4 system; } type tc_switch_block; bool tc_switch_block_b false; if (tc_switch_block_b) { type_change system tc_switch_block:infoflow5 system; type_change system tc_switch_block:infoflow6 system; } else { type_change system tc_switch_block:infoflow7 system; } attribute tc_match_rule_by_attr; type tc_match_rule_by_attr_A_t, tc_match_rule_by_attr; type tc_match_rule_by_attr_B_t, tc_match_rule_by_attr; type_change tc_match_rule_by_attr system:infoflow2 system; attribute tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_A_t, tc_unioned_perm_via_attr; type tc_unioned_perm_via_attr_B_t, tc_unioned_perm_via_attr; type_change tc_unioned_perm_via_attr system:infoflow2 system; type_change tc_unioned_perm_via_attr_A_t system:infoflow2 system; type_change tc_unioned_perm_via_attr_B_t system:infoflow2 system; # type_member rule differences type tm_matched_source; type tm_matched_target; type_member tm_matched_source tm_matched_target:infoflow system; type tm_removed_rule_source; type tm_removed_rule_target; type_member tm_removed_rule_source tm_removed_rule_target:infoflow system; type tm_added_rule_source; type tm_added_rule_target; type tm_old_type; type tm_new_type; type_member tm_matched_source system:infoflow tm_old_type; type_member removed_type system:infoflow4 system; type tm_move_to_bool; bool tm_move_to_bool_b false; type_member tm_move_to_bool system:infoflow3 system; type tm_move_from_bool; bool tm_move_from_bool_b false; if (tm_move_from_bool_b) { type_member tm_move_from_bool system:infoflow4 system; } type tm_switch_block; bool tm_switch_block_b false; if (tm_switch_block_b) { type_member system tm_switch_block:infoflow5 system; type_member system tm_switch_block:infoflow6 system; } else { type_member system tm_switch_block:infoflow7 system; } attribute tm_match_rule_by_attr; type tm_match_rule_by_attr_A_t, tm_match_rule_by_attr; type tm_match_rule_by_attr_B_t, tm_match_rule_by_attr; type_member tm_match_rule_by_attr system:infoflow2 system; attribute tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_A_t, tm_unioned_perm_via_attr; type tm_unioned_perm_via_attr_B_t, tm_unioned_perm_via_attr; type_member tm_unioned_perm_via_attr system:infoflow2 system; type_member tm_unioned_perm_via_attr_A_t system:infoflow2 system; type_member tm_unioned_perm_via_attr_B_t system:infoflow2 system; # range_transition rule differences type rt_matched_source; type rt_matched_target; range_transition rt_matched_source rt_matched_target:infoflow s0; type rt_removed_rule_source; type rt_removed_rule_target; range_transition rt_removed_rule_source rt_removed_rule_target:infoflow s1; type rt_added_rule_source; type rt_added_rule_target; range_transition rt_matched_source system:infoflow s2:c0 - s3:c0.c2; range_transition removed_type system:infoflow4 s1; # range transitions cannot be conditional. #type rt_move_to_bool; #bool rt_move_to_bool_b false; #range_transition rt_move_to_bool system:infoflow3 s0; #type rt_move_from_bool; #bool rt_move_from_bool_b false; #if (rt_move_from_bool_b) { #range_transition rt_move_from_bool system:infoflow4 s0; #} #type rt_switch_block; #bool rt_switch_block_b false; #if (rt_switch_block_b) { #range_transition system rt_switch_block:infoflow5 s0; #range_transition system rt_switch_block:infoflow6 s0; #} else { #range_transition system rt_switch_block:infoflow7 s0; #} attribute rt_match_rule_by_attr; type rt_match_rule_by_attr_A_t, rt_match_rule_by_attr; type rt_match_rule_by_attr_B_t, rt_match_rule_by_attr; range_transition rt_match_rule_by_attr system:infoflow2 s0; attribute rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_A_t, rt_unioned_perm_via_attr; type rt_unioned_perm_via_attr_B_t, rt_unioned_perm_via_attr; range_transition rt_unioned_perm_via_attr system:infoflow2 s0; range_transition rt_unioned_perm_via_attr_A_t system:infoflow2 s0; # role allow role matched_source_r; role matched_target_r; allow matched_source_r matched_target_r; role removed_rule_source_r; role removed_rule_target_r; allow removed_rule_source_r removed_rule_target_r; role added_rule_source_r; role added_rule_target_r; allow removed_role system; # role_transition role role_tr_matched_source; type role_tr_matched_target; role_transition role_tr_matched_source role_tr_matched_target:infoflow system; role role_tr_removed_rule_source; type role_tr_removed_rule_target; role_transition role_tr_removed_rule_source role_tr_removed_rule_target:infoflow5 system; role role_tr_added_rule_source; type role_tr_added_rule_target; role_transition removed_role system:infoflow4 system; role role_tr_old_role; role role_tr_new_role; role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_old_role; # Allowxperm rule differences type ax_matched_source; type ax_matched_target; allowxperm ax_matched_source ax_matched_target:infoflow ioctl 0x0001; type ax_removed_rule_source; type ax_removed_rule_target; allowxperm ax_removed_rule_source ax_removed_rule_target:infoflow ioctl 0x0002; type ax_added_rule_source; type ax_added_rule_target; type ax_modified_rule_add_perms; allowxperm ax_modified_rule_add_perms self:infoflow ioctl 0x0004; type ax_modified_rule_remove_perms; allowxperm ax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type ax_modified_rule_add_remove_perms; allowxperm ax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; allowxperm removed_type self:infoflow7 ioctl 0x0009; attribute ax_match_rule_by_attr; type ax_match_rule_by_attr_A_t, ax_match_rule_by_attr; type ax_match_rule_by_attr_B_t, ax_match_rule_by_attr; allowxperm ax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute ax_union_perm_a; attribute ax_union_perm_b; attribute ax_union_perm_c; type ax_union_perm_source, ax_union_perm_a, ax_union_perm_c; type ax_union_perm_target, ax_union_perm_b; allowxperm ax_union_perm_source ax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Auditallowxperm rule differences type aax_matched_source; type aax_matched_target; auditallowxperm aax_matched_source aax_matched_target:infoflow ioctl 0x0001; type aax_removed_rule_source; type aax_removed_rule_target; auditallowxperm aax_removed_rule_source aax_removed_rule_target:infoflow ioctl 0x0002; type aax_added_rule_source; type aax_added_rule_target; type aax_modified_rule_add_perms; auditallowxperm aax_modified_rule_add_perms self:infoflow ioctl 0x0004; type aax_modified_rule_remove_perms; auditallowxperm aax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type aax_modified_rule_add_remove_perms; auditallowxperm aax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; auditallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute aax_match_rule_by_attr; type aax_match_rule_by_attr_A_t, aax_match_rule_by_attr; type aax_match_rule_by_attr_B_t, aax_match_rule_by_attr; auditallowxperm aax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute aax_union_perm_a; attribute aax_union_perm_b; attribute aax_union_perm_c; type aax_union_perm_source, aax_union_perm_a, aax_union_perm_c; type aax_union_perm_target, aax_union_perm_b; auditallowxperm aax_union_perm_source aax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Neverallowxperm rule differences type nax_matched_source; type nax_matched_target; neverallowxperm nax_matched_source nax_matched_target:infoflow ioctl 0x0001; type nax_removed_rule_source; type nax_removed_rule_target; neverallowxperm nax_removed_rule_source nax_removed_rule_target:infoflow ioctl 0x0002; type nax_added_rule_source; type nax_added_rule_target; type nax_modified_rule_add_perms; neverallowxperm nax_modified_rule_add_perms self:infoflow ioctl 0x0004; type nax_modified_rule_remove_perms; neverallowxperm nax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type nax_modified_rule_add_remove_perms; neverallowxperm nax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; neverallowxperm removed_type self:infoflow7 ioctl 0x0009; attribute nax_match_rule_by_attr; type nax_match_rule_by_attr_A_t, nax_match_rule_by_attr; type nax_match_rule_by_attr_B_t, nax_match_rule_by_attr; neverallowxperm nax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute nax_union_perm_a; attribute nax_union_perm_b; attribute nax_union_perm_c; type nax_union_perm_source, nax_union_perm_a, nax_union_perm_c; type nax_union_perm_target, nax_union_perm_b; neverallowxperm nax_union_perm_source nax_union_perm_target:infoflow ioctl { 0x1-0x3 }; # Dontauditxperm rule differences type dax_matched_source; type dax_matched_target; dontauditxperm dax_matched_source dax_matched_target:infoflow ioctl 0x0001; type dax_removed_rule_source; type dax_removed_rule_target; dontauditxperm dax_removed_rule_source dax_removed_rule_target:infoflow ioctl 0x0002; type dax_added_rule_source; type dax_added_rule_target; type dax_modified_rule_add_perms; dontauditxperm dax_modified_rule_add_perms self:infoflow ioctl 0x0004; type dax_modified_rule_remove_perms; dontauditxperm dax_modified_rule_remove_perms self:infoflow ioctl { 0x0005 0x0006 }; type dax_modified_rule_add_remove_perms; dontauditxperm dax_modified_rule_add_remove_perms self:infoflow2 ioctl { 0x0007 0x0008 }; dontauditxperm removed_type self:infoflow7 ioctl 0x0009; attribute dax_match_rule_by_attr; type dax_match_rule_by_attr_A_t, dax_match_rule_by_attr; type dax_match_rule_by_attr_B_t, dax_match_rule_by_attr; dontauditxperm dax_match_rule_by_attr self:infoflow2 ioctl 0x000a; attribute dax_union_perm_a; attribute dax_union_perm_b; attribute dax_union_perm_c; type dax_union_perm_source, dax_union_perm_a, dax_union_perm_c; type dax_union_perm_target, dax_union_perm_b; dontauditxperm dax_union_perm_source dax_union_perm_target:infoflow ioctl { 0x1-0x3 }; attribute redundant_rule_attr; type redundant_rule_source_1, redundant_rule_attr; type redundant_rule_source_2, redundant_rule_attr; type redundant_rule_target_1; type redundant_rule_target_2; bool redundant_rule_bool true; allow redundant_rule_attr redundant_rule_target_1:infoflow low_w; allow redundant_rule_attr redundant_rule_target_2:infoflow med_w; if (redundant_rule_bool) { allow redundant_rule_source_2 redundant_rule_target_2:infoflow hi_w; } ################################################################################ # matching typebounds type match_parent; type match_child; typebounds match_parent match_child; # removed typebounds type removed_parent; type removed_child; typebounds removed_parent removed_child; # added typebounds type added_parent; type added_child; # modified typebounds type mod_parent_removed; type mod_parent_added; type mod_child; typebounds mod_parent_removed mod_child; # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; user modified_change_range roles system level s3:c1 range s3:c1 - s3:c1.c3; # matching constraints constrain infoflow hi_w (u1 == u2 or t1 == system); constrain infoflow hi_w (t1 == t2 or t1 == system); constrain infoflow hi_r (r1 == r2 or t1 == system); # added constraint # removed constraint constrain infoflow4 hi_w (u1 != u2); # remove/add constraint (expression change) constrain infoflow5 hi_r ((u1 == u2 and r1 == r2) or (t1 == system)); # matching validatetrans validatetrans infoflow (u1 == u2 or t3 == system); validatetrans infoflow (r1 == r2 or t3 == system); validatetrans infoflow2 (u1 == u2 or t3 == system); # added validatetrans # removed validatetrans validatetrans infoflow4 (u1 == u2 or t3 == system); # remove/add validatetrans (expression change) validatetrans infoflow5 ((u1 == u2 and r1 != r2) or (t3 == system)); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid unlabeled system:system:system:s0 sid fs removed_user:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 121.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff01:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 # removed nodecons nodecon 122.0.0.0 255.0.0.0 removed_user:object_r:system:s0 nodecon ff02:: ffff:ffff:ffff:fffc:: removed_user:object_r:system:s0 # modified nodecons nodecon 123.0.0.0 255.0.0.0 modified_change_level:object_r:system:s2:c1 nodecon ff03:: ffff:ffff:ffff:fffc:: modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 125.0.0.0 255.0.0.0 system:object_r:system:s0 nodecon ff05:: ffff:ffff:ffff:fffc:: system:object_r:system:s0 setools-4.4.0/tests/dta.conf000066400000000000000000000130331402045477700160020ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class process class file class sock_file sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class process { transition dyntransition setexec setcurrent } class file { execute entrypoint } class sock_file { execute } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Domain transition analysis # # The extent of the valid transition graph: # # start -> trans1 -> trans2 -> trans3 -> trans5 # | # | -> dyntrans100 -> bothtrans200 # # Everything else is invalid # test 1 # type_transition start -> trans1 type start; type trans1; type trans1_exec; allow start trans1:process transition; allow start trans1_exec:file execute; allow trans1 trans1_exec:file entrypoint; type_transition start trans1_exec:process trans1; # test 2 # setexec trans1 -> trans2 type trans2; type trans2_exec; allow trans1 self:process setexec; allow trans1 trans2:process transition; allow trans1 trans2_exec:file execute; allow trans2 trans2_exec:file entrypoint; # test 3 # type_transiton and setexec trans2 -> trans3 # 2 entrypoints type trans3; type trans3_exec1; type trans3_exec2; allow trans2 self:process setexec; allow trans2 trans3:process transition; allow trans2 { trans3_exec1 trans3_exec2 }:file execute; allow trans3 { trans3_exec1 trans3_exec2 }:file entrypoint; type_transition trans2 trans3_exec1:process trans3; # test 4 # invalid transition, no type_transition/setexec type trans4; type trans4_exec; allow start trans4:process transition; allow start trans4_exec:file execute; allow trans4 trans4_exec:file entrypoint; # test 5 # type_transition trans3 -> trans5 # 1 entrypoint w/conditional type_trans # This makes sure the type_transition fully # matches as expected. type trans5; type trans5_exec; bool trans5 false; allow trans3 trans5:process transition; allow trans3 trans5_exec:file execute; allow trans5 trans5_exec:file entrypoint; if(trans5) { type_transition trans3 trans5_exec:process trans5; } else { type_transition trans3 trans5_exec:process trans4; } # test 100 # dyntrans start -> dyntrans100 type dyntrans100; allow start self:process setcurrent; allow start dyntrans100:process dyntransition; # test 101 # invalid dyntransition, no setcurrent type dyntrans101; type dyntrans102; allow dyntrans101 dyntrans102:process dyntransition; # test 200 # all transition possiblities dyntrans100 -> bothtrans200 type bothtrans200; type bothtrans200_exec; allow dyntrans100 self:process { setexec setcurrent }; allow dyntrans100 bothtrans200:process { transition dyntransition }; allow dyntrans100 bothtrans200_exec:file execute; allow bothtrans200 bothtrans200_exec:file entrypoint; type_transition dyntrans100 bothtrans200_exec:process bothtrans200; # test 201 # no loops in graph type bothtrans201; type bothtrans201_exec; allow bothtrans201 self:process { setexec setcurrent }; allow bothtrans201 bothtrans201:process { transition dyntransition }; allow bothtrans201 bothtrans201_exec:file { execute entrypoint }; # test 300 # auditallow by itself does not work for execute perms type trans300; type trans300_exec; allow start trans300:process transition; auditallow start trans300_exec:file execute; allow trans300 trans300_exec:file entrypoint; type_transition start trans300_exec:process trans300; # test 301 # wrong class for type transition type trans301; type trans301_exec; allow start trans301:process transition; allow start trans301_exec:file execute; allow trans301 trans301_exec:file entrypoint; type_transition start trans301_exec:file trans301; # test 302 # wrong class for exec perms type trans302; type trans302_exec; allow start trans302:process transition; allow start trans302_exec:sock_file execute; allow trans302 trans302_exec:file entrypoint; type_transition start trans302_exec:file trans302; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/dta.py000066400000000000000000001072721402045477700155160ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import DomainTransitionAnalysis from setools import TERuletype as TERT from setools.exception import InvalidType from setools.policyrep import Type from . import mixins from .policyrep.util import compile_policy class DomainTransitionAnalysisTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/dta.conf") cls.a = DomainTransitionAnalysis(cls.p) cls.a._build_graph() @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_graph_structure(self): """DTA: verify graph structure.""" # don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.G.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_001_bothtrans(self): """DTA: type_transition, setexeccon(), and setcon() transitions.""" s = self.p.lookup_type("dyntrans100") t = self.p.lookup_type("bothtrans200") e = self.p.lookup_type("bothtrans200_exec") # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition", "dyntransition"])) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec", "setcurrent"])) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t) # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition", "dyntransition"])) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec", "setcurrent"])) def test_010_dyntrans(self): """DTA: setcon() transition.""" s = self.p.lookup_type("start") t = self.p.lookup_type("dyntrans100") # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 0) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(len(k), 0) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(len(k), 0) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(len(k), 0) # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["dyntransition"])) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setcurrent"])) def test_020_trans(self): """DTA: type_transition transition.""" s = self.p.lookup_type("start") t = self.p.lookup_type("trans1") e = self.p.lookup_type("trans1_exec") # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t) # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 0) def test_030_setexec(self): """DTA: setexec() transition.""" s = self.p.lookup_type("trans1") t = self.p.lookup_type("trans2") e = self.p.lookup_type("trans2_exec") # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec"])) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(len(k), 0) # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 0) def test_040_two_entrypoint(self): """DTA: 2 entrypoints, only one by type_transition.""" s = self.p.lookup_type("trans2") t = self.p.lookup_type("trans3") e = [self.p.lookup_type("trans3_exec1"), self.p.lookup_type("trans3_exec2")] # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, s, "process", set(["setexec"])) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(k, e) r = self.a.G.edges[s, t]["execute"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e[0], "file", set(["execute"])) r = self.a.G.edges[s, t]["execute"][e[1]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e[1], "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(k, e) r = self.a.G.edges[s, t]["entrypoint"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e[0], "file", set(["entrypoint"])) r = self.a.G.edges[s, t]["entrypoint"][e[1]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e[1], "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(k, [e[0]]) r = self.a.G.edges[s, t]["type_transition"][e[0]] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e[0], "process", t) # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 0) def test_050_cond_type_trans(self): """DTA: conditional type_transition.""" s = self.p.lookup_type("trans3") t = self.p.lookup_type("trans5") e = self.p.lookup_type("trans5_exec") # regular transition r = self.a.G.edges[s, t]["transition"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, t, "process", set(["transition"])) # setexec perms r = self.a.G.edges[s, t]["setexec"] self.assertEqual(len(r), 0) # exec perms k = sorted(self.a.G.edges[s, t]["execute"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["execute"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, s, e, "file", set(["execute"])) # entrypoint perms k = sorted(self.a.G.edges[s, t]["entrypoint"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["entrypoint"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, t, e, "file", set(["entrypoint"])) # type_transition k = sorted(self.a.G.edges[s, t]["type_transition"].keys()) self.assertEqual(k, [e]) r = self.a.G.edges[s, t]["type_transition"][e] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.type_transition, s, e, "process", t, cond="trans5") # dynamic transition r = self.a.G.edges[s, t]["dyntransition"] self.assertEqual(len(r), 0) # setcurrent r = self.a.G.edges[s, t]["setcurrent"] self.assertEqual(len(r), 0) def test_100_forward_subgraph_structure(self): """DTA: verify forward subgraph structure.""" # The purpose is to ensure the subgraph is reversed # only when the reverse option is set, not that # graph reversal is correct (assumed that NetworkX # does it correctly). # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_101_reverse_subgraph_structure(self): """DTA: verify reverse subgraph structure.""" # The purpose is to ensure the subgraph is reversed # only when the reverse option is set, not that # graph reversal is correct (assumed that NetworkX # does it correctly). # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = True self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(bothtrans200, dyntrans100), (dyntrans100, start), (trans1, start), (trans2, trans1), (trans3, trans2), (trans5, trans3)]), edges) def test_200_exclude_domain(self): """DTA: exclude domain type.""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans1"] self.a._build_subgraph() start = self.p.lookup_type("start") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (trans2, trans3), (trans3, trans5)]), edges) def test_201_exclude_entryoint_with_2entrypoints(self): """DTA: exclude entrypoint type without transition deletion (other entrypoints).""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans3_exec1"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_202_exclude_entryoint_with_dyntrans(self): """DTA: exclude entrypoint type without transition deletion (dyntrans).""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["bothtrans200_exec"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans1, trans2), (trans2, trans3), (trans3, trans5)]), edges) def test_203_exclude_entryoint_delete_transition(self): """DTA: exclude entrypoint type with transition deletion.""" # Don't check node list since the disconnected nodes are not # removed after removing invalid domain transitions self.a.reverse = False self.a.exclude = ["trans2_exec"] self.a._build_subgraph() start = self.p.lookup_type("start") trans1 = self.p.lookup_type("trans1") trans2 = self.p.lookup_type("trans2") trans3 = self.p.lookup_type("trans3") trans5 = self.p.lookup_type("trans5") dyntrans100 = self.p.lookup_type("dyntrans100") bothtrans200 = self.p.lookup_type("bothtrans200") edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(dyntrans100, bothtrans200), (start, dyntrans100), (start, trans1), (trans2, trans3), (trans3, trans5)]), edges) def test_300_all_paths(self): """DTA: all paths output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.all_paths("start", "bothtrans200", 3)) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum + 1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_301_all_shortest_paths(self): """DTA: all shortest paths output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.all_shortest_paths("start", "bothtrans200")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum + 1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_302_shortest_path(self): """DTA: shortest path output""" self.a.reverse = False self.a.exclude = None expected_path = ["start", "dyntrans100", "bothtrans200"] paths = list(self.a.shortest_path("start", "bothtrans200")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum], step.source) self.assertEqual(expected_path[stepnum + 1], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_303_transitions(self): """DTA: transitions output""" self.a.reverse = False self.a.exclude = None transitions = list(self.a.transitions("start")) self.assertEqual(2, len(transitions)) for step in transitions: self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual("start", step.source) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_310_all_paths_reversed(self): """DTA: all paths output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.all_paths("bothtrans200", "start", 3)) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, expected_path[stepnum + 1]) self.assertEqual(step.target, expected_path[stepnum]) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_311_all_shortest_paths_reversed(self): """DTA: all shortest paths output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.all_shortest_paths("bothtrans200", "start")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, expected_path[stepnum + 1]) self.assertEqual(step.target, expected_path[stepnum]) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_312_shortest_path_reversed(self): """DTA: shortest path output reverse DTA""" self.a.reverse = True self.a.exclude = None expected_path = ["bothtrans200", "dyntrans100", "start"] paths = list(self.a.shortest_path("bothtrans200", "start")) self.assertEqual(1, len(paths)) for path in paths: for stepnum, step in enumerate(path): self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(expected_path[stepnum + 1], step.source) self.assertEqual(expected_path[stepnum], step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_313_transitions_reversed(self): """DTA: transitions output reverse DTA""" self.a.reverse = True self.a.exclude = None transitions = list(self.a.transitions("bothtrans200")) self.assertEqual(1, len(transitions)) for step in transitions: self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual("bothtrans200", step.target) for r in step.transition: self.assertIn("transition", r.perms) for e in step.entrypoints: self.assertIsInstance(e.name, Type) for r in e.entrypoint: self.assertIn("entrypoint", r.perms) for r in e.execute: self.assertIn("execute", r.perms) for r in e.type_transition: self.assertEqual(TERT.type_transition, r.ruletype) for r in step.setexec: self.assertIn("setexec", r.perms) for r in step.dyntransition: self.assertIn("dyntransition", r.perms) for r in step.setcurrent: self.assertIn("setcurrent", r.perms) def test_900_set_exclude_invalid_type(self): """DTA: set invalid excluded type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): self.a.exclude = ["trans1", "invalid_type"] def test_910_all_paths_invalid_source(self): """DTA: all paths with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_paths("invalid_type", "trans1")) def test_911_all_paths_invalid_target(self): """DTA: all paths with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_paths("trans1", "invalid_type")) def test_912_all_paths_invalid_maxlen(self): """DTA: all paths with invalid max path length.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(ValueError): list(self.a.all_paths("trans1", "trans2", maxlen=-2)) def test_913_all_paths_source_excluded(self): """DTA: all paths with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.all_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_914_all_paths_target_excluded(self): """DTA: all paths with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.all_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_915_all_paths_source_disconnected(self): """DTA: all paths with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.all_paths("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_916_all_paths_target_disconnected(self): """DTA: all paths with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.all_paths("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_920_shortest_path_invalid_source(self): """DTA: shortest path with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.shortest_path("invalid_type", "trans1")) def test_921_shortest_path_invalid_target(self): """DTA: shortest path with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.shortest_path("trans1", "invalid_type")) def test_922_shortest_path_source_excluded(self): """DTA: shortest path with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.shortest_path("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_923_shortest_path_target_excluded(self): """DTA: shortest path with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.shortest_path("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_924_shortest_path_source_disconnected(self): """DTA: shortest path with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.shortest_path("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_925_shortest_path_target_disconnected(self): """DTA: shortest path with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.shortest_path("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_930_all_shortest_paths_invalid_source(self): """DTA: all shortest paths with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("invalid_type", "trans1")) def test_931_all_shortest_paths_invalid_target(self): """DTA: all shortest paths with invalid target type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("trans1", "invalid_type")) def test_932_all_shortest_paths_source_excluded(self): """DTA: all shortest paths with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.all_shortest_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_933_all_shortest_paths_target_excluded(self): """DTA: all shortest paths with excluded target type.""" self.a.reverse = False self.a.exclude = ["trans2"] paths = list(self.a.all_shortest_paths("trans1", "trans2")) self.assertEqual(0, len(paths)) def test_934_all_shortest_paths_source_disconnected(self): """DTA: all shortest paths with disconnected source type.""" self.a.reverse = False self.a.exclude = None paths = list(self.a.all_shortest_paths("trans5", "trans2")) self.assertEqual(0, len(paths)) def test_935_all_shortest_paths_target_disconnected(self): """DTA: all shortest paths with disconnected target type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.all_shortest_paths("trans2", "trans5")) self.assertEqual(0, len(paths)) def test_940_transitions_invalid_source(self): """DTA: transitions with invalid source type.""" self.a.reverse = False self.a.exclude = None with self.assertRaises(InvalidType): list(self.a.transitions("invalid_type")) def test_941_transitions_source_excluded(self): """DTA: transitions with excluded source type.""" self.a.reverse = False self.a.exclude = ["trans1"] paths = list(self.a.transitions("trans1")) self.assertEqual(0, len(paths)) def test_942_transitions_source_disconnected(self): """DTA: transitions with disconnected source type.""" self.a.reverse = False self.a.exclude = ["trans3"] paths = list(self.a.transitions("trans5")) self.assertEqual(0, len(paths)) setools-4.4.0/tests/fsusequery.conf000066400000000000000000000123651402045477700174540ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use # test 1: # ruletype: unset # fs: test1, exact # user: unset # role: unset # type: unset # range: unset fs_use_xattr test1 system:system:system:s0:c0.c4; # test 2: # ruletype: unset # fs: test2(a|b), regex # user: unset # role: unset # type: unset # range: unset fs_use_xattr test2a system:system:system:s0:c0.c1; fs_use_xattr test2b system:system:system:s0:c2.c4; # test 10: # ruletype: ['fs_use_trans','fs_use_task'] # fs: unset # user: unset # role: unset # type: unset # range: unset fs_use_trans test10a system:system:system:s0:c0.c1; fs_use_task test10b system:system:system:s0:c2.c4; fs_use_xattr test10c system:system:system:s0:c2; # test 20: # ruletype: unset # fs: unset # user: user20, exact # role: unset # type: unset # range: unset fs_use_xattr test20 user20:system:system:s0:c0.c1; # test 21: # ruletype: unset # fs: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset fs_use_xattr test21a user21a:system:system:s0:c0.c1; fs_use_xattr test21b user21b:system:system:s0:c0.c1; fs_use_xattr test21c user21c:system:system:s0:c0.c1; # test 30: # ruletype: unset # fs: unset # user: unset # role: role30_r, exact # type: unset # range: unset fs_use_xattr test30 system:role30_r:system:s0:c0.c1; # test 31: # ruletype: unset # fs: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset fs_use_xattr test31a system:role31a_r:system:s0:c0.c1; fs_use_xattr test31b system:role31b_r:system:s0:c0.c1; fs_use_xattr test31c system:role31c_r:system:s0:c0.c1; # test 40: # ruletype: unset # fs: unset # user: unset # role: unset # type: type40 # range: unset fs_use_xattr test40 system:system:type40:s0:c0.c1; # test 41: # ruletype: unset # fs: unset # user: unset # role: unset # type: type41(b|c) # range: unset fs_use_xattr test41a system:system:type41a:s0:c0.c1; fs_use_xattr test41b system:system:type41b:s0:c0.c1; fs_use_xattr test41c system:system:type41c:s0:c0.c1; # test 50: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: equal fs_use_xattr test50 system:system:system:s0:c1 - s0:c0.c4; # test 51: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: overlap fs_use_xattr test51 system:system:system:s1:c1 - s1:c1.c3; # test 52: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: subset fs_use_xattr test52 system:system:system:s2:c1 - s2:c1.c3; # test 53: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: superset fs_use_xattr test53 system:system:system:s3:c1 - s3:c1.c3; # test 54: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: proper subset fs_use_xattr test54 system:system:system:s4:c1 - s4:c1.c3; # test 55: # ruletype: unset # fs: unset # user: unset # role: unset # type: unset # range: proper superset fs_use_xattr test55 system:system:system:s5:c1 - s5:c1.c3; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/fsusequery.py000066400000000000000000000213671402045477700171610ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import FSUseQuery from .policyrep.util import compile_policy class FSUseQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/fsusequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """fs_use_* query with no criteria""" # query with no parameters gets all fs_use_*. fsu = sorted(self.p.fs_uses()) q = FSUseQuery(self.p) q_fsu = sorted(q.results()) self.assertListEqual(fsu, q_fsu) def test_001_fs_exact(self): """fs_use_* query with exact fs match""" q = FSUseQuery(self.p, fs="test1", fs_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test1"], fsu) def test_002_fs_regex(self): """fs_use_* query with regex fs match""" q = FSUseQuery(self.p, fs="test2(a|b)", fs_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test2a", "test2b"], fsu) def test_010_ruletype(self): """fs_use_* query with ruletype match""" q = FSUseQuery(self.p, ruletype=['fs_use_trans', 'fs_use_task']) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test10a", "test10b"], fsu) def test_020_user_exact(self): """fs_use_* query with context user exact match""" q = FSUseQuery(self.p, user="user20", user_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test20"], fsu) def test_021_user_regex(self): """fs_use_* query with context user regex match""" q = FSUseQuery(self.p, user="user21(a|b)", user_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test21a", "test21b"], fsu) def test_030_role_exact(self): """fs_use_* query with context role exact match""" q = FSUseQuery(self.p, role="role30_r", role_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test30"], fsu) def test_031_role_regex(self): """fs_use_* query with context role regex match""" q = FSUseQuery(self.p, role="role31(a|c)_r", role_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test31a", "test31c"], fsu) def test_040_type_exact(self): """fs_use_* query with context type exact match""" q = FSUseQuery(self.p, type_="type40", type_regex=False) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test40"], fsu) def test_041_type_regex(self): """fs_use_* query with context type regex match""" q = FSUseQuery(self.p, type_="type41(b|c)", type_regex=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test41b", "test41c"], fsu) def test_050_range_exact(self): """fs_use_* query with context range exact match""" q = FSUseQuery(self.p, range_="s0:c1 - s0:c0.c4") fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test50"], fsu) def test_051_range_overlap1(self): """fs_use_* query with context range overlap match (equal)""" q = FSUseQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap2(self): """fs_use_* query with context range overlap match (subset)""" q = FSUseQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap3(self): """fs_use_* query with context range overlap match (superset)""" q = FSUseQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap4(self): """fs_use_* query with context range overlap match (overlap low level)""" q = FSUseQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_051_range_overlap5(self): """fs_use_* query with context range overlap match (overlap high level)""" q = FSUseQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test51"], fsu) def test_052_range_subset1(self): """fs_use_* query with context range subset match""" q = FSUseQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test52"], fsu) def test_052_range_subset2(self): """fs_use_* query with context range subset match (equal)""" q = FSUseQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test52"], fsu) def test_053_range_superset1(self): """fs_use_* query with context range superset match""" q = FSUseQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test53"], fsu) def test_053_range_superset2(self): """fs_use_* query with context range superset match (equal)""" q = FSUseQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test53"], fsu) def test_054_range_proper_subset1(self): """fs_use_* query with context range proper subset match""" q = FSUseQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_054_range_proper_subset2(self): """fs_use_* query with context range proper subset match (equal)""" q = FSUseQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual([], fsu) def test_054_range_proper_subset3(self): """fs_use_* query with context range proper subset match (equal low only)""" q = FSUseQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_054_range_proper_subset4(self): """fs_use_* query with context range proper subset match (equal high only)""" q = FSUseQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test54"], fsu) def test_055_range_proper_superset1(self): """fs_use_* query with context range proper superset match""" q = FSUseQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) def test_055_range_proper_superset2(self): """fs_use_* query with context range proper superset match (equal)""" q = FSUseQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual([], fsu) def test_055_range_proper_superset3(self): """fs_use_* query with context range proper superset match (equal low)""" q = FSUseQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) def test_055_range_proper_superset4(self): """fs_use_* query with context range proper superset match (equal high)""" q = FSUseQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) fsu = sorted(s.fs for s in q.results()) self.assertListEqual(["test55"], fsu) setools-4.4.0/tests/genfsconquery.conf000066400000000000000000000142341402045477700201260ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class file class dir class infoflow6 class lnk_file class chr_file class blk_file class sock_file class fifo_file class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class dir inherits infoflow class file inherits infoflow class lnk_file inherits infoflow class sock_file inherits infoflow class fifo_file inherits infoflow class chr_file inherits infoflow class blk_file inherits infoflow sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon # test 1: # fs: test1, exact # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test1 / system:system:system:s0:c0.c4 # test 2: # fs: test2(a|b), regex # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test2a / system:system:system:s0:c0.c1 genfscon test2b / system:system:system:s0:c2.c4 # test 10: # fs: unset # path: /sys, exact # user: unset # role: unset # type: unset # range: unset genfscon test10 /sys system:system:system:s0:c2.c4 # test 11: # fs: unset # path: /(spam|eggs), regex # user: unset # role: unset # type: unset # range: unset genfscon test11a /spam system:system:system:s0:c2.c4 genfscon test11b /eggs system:system:system:s0:c2.c4 genfscon test11c /FAIL system:system:system:s0:c2.c4 # test 20: # fs: unset # path: unset # user: user20, exact # role: unset # type: unset # range: unset genfscon test20 / user20:system:system:s0:c0.c1 # test 21: # fs: unset # path: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset genfscon test21a / user21a:system:system:s0:c0.c1 genfscon test21b / user21b:system:system:s0:c0.c1 genfscon test21c / user21c:system:system:s0:c0.c1 # test 30: # fs: unset # path: unset # user: unset # role: role30_r, exact # type: unset # range: unset genfscon test30 / system:role30_r:system:s0:c0.c1 # test 31: # fs: unset # path: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset genfscon test31a / system:role31a_r:system:s0:c0.c1 genfscon test31b / system:role31b_r:system:s0:c0.c1 genfscon test31c / system:role31c_r:system:s0:c0.c1 # test 40: # fs: unset # path: unset # user: unset # role: unset # type: type40 # range: unset genfscon test40 / system:system:type40:s0:c0.c1 # test 41: # fs: unset # path: unset # user: unset # role: unset # type: type41(b|c) # range: unset genfscon test41a / system:system:type41a:s0:c0.c1 genfscon test41b / system:system:type41b:s0:c0.c1 genfscon test41c / system:system:type41c:s0:c0.c1 # test 50: # fs: unset # filetype: -b # path: unset # user: unset # role: unset # type: unset # range: unset genfscon test50f / -- system:system:system:s0:c0.c4 genfscon test50b / -b system:system:system:s0:c0.c4 genfscon test50c / -c system:system:system:s0:c0.c4 genfscon test50s / -s system:system:system:s0:c0.c4 genfscon test50l / -l system:system:system:s0:c0.c4 genfscon test50p / -p system:system:system:s0:c0.c4 genfscon test50d / -d system:system:system:s0:c0.c4 # test 60: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: equal genfscon test60 / system:system:system:s0:c1 - s0:c0.c4 # test 61: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: overlap genfscon test61 / system:system:system:s1:c1 - s1:c1.c3 # test 62: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: subset genfscon test62 / system:system:system:s2:c1 - s2:c1.c3 # test 63: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: superset genfscon test63 / system:system:system:s3:c1 - s3:c1.c3 # test 64: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: proper subset genfscon test64 / system:system:system:s4:c1 - s4:c1.c3 # test 65: # fs: unset # filetype: unset # path: unset # user: unset # role: unset # type: unset # range: proper superset genfscon test65 / system:system:system:s5:c1 - s5:c1.c3 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/genfsconquery.py000066400000000000000000000227321402045477700176330ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest import stat from setools import GenfsconQuery from .policyrep.util import compile_policy class GenfsconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/genfsconquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Genfscon query with no criteria""" # query with no parameters gets all genfs. genfs = sorted(self.p.genfscons()) q = GenfsconQuery(self.p) q_genfs = sorted(q.results()) self.assertListEqual(genfs, q_genfs) def test_001_fs_exact(self): """Genfscon query with exact fs match""" q = GenfsconQuery(self.p, fs="test1", fs_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test1"], genfs) def test_002_fs_regex(self): """Genfscon query with regex fs match""" q = GenfsconQuery(self.p, fs="test2(a|b)", fs_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test2a", "test2b"], genfs) def test_010_path_exact(self): """Genfscon query with exact path match""" q = GenfsconQuery(self.p, path="/sys", path_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test10"], genfs) def test_011_path_regex(self): """Genfscon query with regex path match""" q = GenfsconQuery(self.p, path="/(spam|eggs)", path_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test11a", "test11b"], genfs) def test_020_user_exact(self): """Genfscon query with context user exact match""" q = GenfsconQuery(self.p, user="user20", user_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test20"], genfs) def test_021_user_regex(self): """Genfscon query with context user regex match""" q = GenfsconQuery(self.p, user="user21(a|b)", user_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test21a", "test21b"], genfs) def test_030_role_exact(self): """Genfscon query with context role exact match""" q = GenfsconQuery(self.p, role="role30_r", role_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test30"], genfs) def test_031_role_regex(self): """Genfscon query with context role regex match""" q = GenfsconQuery(self.p, role="role31(a|c)_r", role_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test31a", "test31c"], genfs) def test_040_type_exact(self): """Genfscon query with context type exact match""" q = GenfsconQuery(self.p, type_="type40", type_regex=False) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test40"], genfs) def test_041_type_regex(self): """Genfscon query with context type regex match""" q = GenfsconQuery(self.p, type_="type41(b|c)", type_regex=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test41b", "test41c"], genfs) def test_050_file_type(self): """Genfscon query with file type match""" q = GenfsconQuery(self.p, filetype=stat.S_IFBLK) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test50b"], genfs) def test_060_range_exact(self): """Genfscon query with context range exact match""" q = GenfsconQuery(self.p, range_="s0:c1 - s0:c0.c4") genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test60"], genfs) def test_061_range_overlap1(self): """Genfscon query with context range overlap match (equal)""" q = GenfsconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap2(self): """Genfscon query with context range overlap match (subset)""" q = GenfsconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap3(self): """Genfscon query with context range overlap match (superset)""" q = GenfsconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap4(self): """Genfscon query with context range overlap match (overlap low level)""" q = GenfsconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_061_range_overlap5(self): """Genfscon query with context range overlap match (overlap high level)""" q = GenfsconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test61"], genfs) def test_062_range_subset1(self): """Genfscon query with context range subset match""" q = GenfsconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test62"], genfs) def test_062_range_subset2(self): """Genfscon query with context range subset match (equal)""" q = GenfsconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test62"], genfs) def test_063_range_superset1(self): """Genfscon query with context range superset match""" q = GenfsconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test63"], genfs) def test_063_range_superset2(self): """Genfscon query with context range superset match (equal)""" q = GenfsconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test63"], genfs) def test_064_range_proper_subset1(self): """Genfscon query with context range proper subset match""" q = GenfsconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_064_range_proper_subset2(self): """Genfscon query with context range proper subset match (equal)""" q = GenfsconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual([], genfs) def test_064_range_proper_subset3(self): """Genfscon query with context range proper subset match (equal low only)""" q = GenfsconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_064_range_proper_subset4(self): """Genfscon query with context range proper subset match (equal high only)""" q = GenfsconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test64"], genfs) def test_065_range_proper_superset1(self): """Genfscon query with context range proper superset match""" q = GenfsconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) def test_065_range_proper_superset2(self): """Genfscon query with context range proper superset match (equal)""" q = GenfsconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual([], genfs) def test_065_range_proper_superset3(self): """Genfscon query with context range proper superset match (equal low)""" q = GenfsconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) def test_065_range_proper_superset4(self): """Genfscon query with context range proper superset match (equal high)""" q = GenfsconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) genfs = sorted(s.fs for s in q.results()) self.assertListEqual(["test65"], genfs) setools-4.4.0/tests/ibendportconquery.conf000066400000000000000000000122641402045477700210130ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 # test 1: # name: test1, exact # port: unset # user: unset # role: unset # type: unset # range: unset ibendportcon test1 1 system:system:system:s0:c0.c1 # test 2: # name: test2(a|b), regex # port: unset # user: unset # role: unset # type: unset # range: unset ibendportcon test2a 2 system:system:system:s0:c0.c1 ibendportcon test2b 3 system:system:system:s0:c0.c1 ibendportcon test2c 4 system:system:system:s0:c0.c1 # test 10: # name: unset # port: 10 # user: unset # role: unset # type: unset # range: unset ibendportcon test10 10 system:system:system:s0:c0.c1 # test 20: # name: unset # port: unset # user: user20, exact # role: unset # type: unset # range: unset ibendportcon test20 20 user20:system:system:s0:c0.c1 # test 21: # name: unset # port: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset ibendportcon test21a 21 user21a:system:system:s0:c0.c1 ibendportcon test21b 22 user21b:system:system:s0:c0.c1 ibendportcon test21c 23 user21c:system:system:s0:c0.c1 # test 30: # name: unset # port: unset # user: unset # role: role30_r, exact # type: unset # range: unset ibendportcon test30 30 system:role30_r:system:s0:c0.c1 # test 31: # name: unset # port: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset ibendportcon test31a 31 system:role31a_r:system:s0:c0.c1 ibendportcon test31b 32 system:role31b_r:system:s0:c0.c1 ibendportcon test31c 33 system:role31c_r:system:s0:c0.c1 # test 40: # name: unset # port: unset # user: unset # role: unset # type: type40 # range: unset ibendportcon test40 40 system:system:type40:s0:c0.c1 # test 41: # name: unset # port: unset # user: unset # role: unset # type: type41(b|c) # range: unset ibendportcon test41a 41 system:system:type41a:s0:c0.c1 ibendportcon test41b 42 system:system:type41b:s0:c0.c1 ibendportcon test41c 43 system:system:type41c:s0:c0.c1 # test 50: # name: unset # port: unset # user: unset # role: unset # type: unset # range: equal ibendportcon test50 50 system:system:system:s0:c1 - s0:c0.c4 # test 51: # name: unset # port: unset # user: unset # role: unset # type: unset # range: overlap ibendportcon test51 51 system:system:system:s1:c1 - s1:c1.c3 # test 52: # name: unset # port: unset # user: unset # role: unset # type: unset # range: subset ibendportcon test52 52 system:system:system:s2:c1 - s2:c1.c3 # test 53: # name: unset # port: unset # user: unset # role: unset # type: unset # range: superset ibendportcon test53 53 system:system:system:s3:c1 - s3:c1.c3 # test 54: # name: unset # port: unset # user: unset # role: unset # type: unset # range: proper subset ibendportcon test54 54 system:system:system:s4:c1 - s4:c1.c3 # test 55: # name: unset # port: unset # user: unset # role: unset # type: unset # range: proper superset ibendportcon test55 55 system:system:system:s5:c1 - s5:c1.c3 setools-4.4.0/tests/ibendportconquery.py000066400000000000000000000236021402045477700205140ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import IbendportconQuery from .policyrep.util import compile_policy class IbendportconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/ibendportconquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Ibendportcon query with no criteria""" # query with no parameters gets all ibendportcons. ibendportcons = sorted(self.p.ibendportcons()) q = IbendportconQuery(self.p) q_ibendportcons = sorted(q.results()) self.assertListEqual(ibendportcons, q_ibendportcons) def test_001_name_exact(self): """Ibendportcon query with exact name match.""" q = IbendportconQuery(self.p, name="test1", name_regex=False) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test1"], ibendportcons) def test_002_name_regext(self): """Ibendportcon query with regex name match.""" q = IbendportconQuery(self.p, name="test2(a|b)", name_regex=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test2a", "test2b"], ibendportcons) def test_010_port(self): """Ibendportcon query with port match.""" q = IbendportconQuery(self.p, port=10) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test10"], ibendportcons) def test_020_user_exact(self): """Ibendportcon query with context user exact match""" q = IbendportconQuery(self.p, user="user20", user_regex=False) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test20"], ibendportcons) def test_021_user_regex(self): """Ibendportcon query with context user regex match""" q = IbendportconQuery(self.p, user="user21(a|b)", user_regex=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test21a", "test21b"], ibendportcons) def test_030_role_exact(self): """Ibendportcon query with context role exact match""" q = IbendportconQuery(self.p, role="role30_r", role_regex=False) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test30"], ibendportcons) def test_031_role_regex(self): """Ibendportcon query with context role regex match""" q = IbendportconQuery(self.p, role="role31(a|c)_r", role_regex=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test31a", "test31c"], ibendportcons) def test_040_type_exact(self): """Ibendportcon query with context type exact match""" q = IbendportconQuery(self.p, type_="type40", type_regex=False) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test40"], ibendportcons) def test_041_type_regex(self): """Ibendportcon query with context type regex match""" q = IbendportconQuery(self.p, type_="type41(b|c)", type_regex=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test41b", "test41c"], ibendportcons) def test_050_range_exact(self): """Ibendportcon query with context range exact match""" q = IbendportconQuery(self.p, range_="s0:c1 - s0:c0.c4") ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test50"], ibendportcons) def test_051_range_overlap1(self): """Ibendportcon query with context range overlap match (equal)""" q = IbendportconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test51"], ibendportcons) def test_051_range_overlap2(self): """Ibendportcon query with context range overlap match (subset)""" q = IbendportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test51"], ibendportcons) def test_051_range_overlap3(self): """Ibendportcon query with context range overlap match (superset)""" q = IbendportconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test51"], ibendportcons) def test_051_range_overlap4(self): """Ibendportcon query with context range overlap match (overlap low level)""" q = IbendportconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test51"], ibendportcons) def test_051_range_overlap5(self): """Ibendportcon query with context range overlap match (overlap high level)""" q = IbendportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test51"], ibendportcons) def test_052_range_subset1(self): """Ibendportcon query with context range subset match""" q = IbendportconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test52"], ibendportcons) def test_052_range_subset2(self): """Ibendportcon query with context range subset match (equal)""" q = IbendportconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test52"], ibendportcons) def test_053_range_superset1(self): """Ibendportcon query with context range superset match""" q = IbendportconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test53"], ibendportcons) def test_053_range_superset2(self): """Ibendportcon query with context range superset match (equal)""" q = IbendportconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test53"], ibendportcons) def test_054_range_proper_subset1(self): """Ibendportcon query with context range proper subset match""" q = IbendportconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test54"], ibendportcons) def test_054_range_proper_subset2(self): """Ibendportcon query with context range proper subset match (equal)""" q = IbendportconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual([], ibendportcons) def test_054_range_proper_subset3(self): """Ibendportcon query with context range proper subset match (equal low only)""" q = IbendportconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test54"], ibendportcons) def test_054_range_proper_subset4(self): """Ibendportcon query with context range proper subset match (equal high only)""" q = IbendportconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test54"], ibendportcons) def test_055_range_proper_superset1(self): """Ibendportcon query with context range proper superset match""" q = IbendportconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test55"], ibendportcons) def test_055_range_proper_superset2(self): """Ibendportcon query with context range proper superset match (equal)""" q = IbendportconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual([], ibendportcons) def test_055_range_proper_superset3(self): """Ibendportcon query with context range proper superset match (equal low)""" q = IbendportconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test55"], ibendportcons) def test_055_range_proper_superset4(self): """Ibendportcon query with context range proper superset match (equal high)""" q = IbendportconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ibendportcons = sorted(n.name for n in q.results()) self.assertListEqual(["test55"], ibendportcons) setools-4.4.0/tests/ibpkeyconquery.conf000066400000000000000000000120311402045477700203000ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 # test 1: # subnet_prefix: fe81:: # pkeys: unset # user: unset # role: unset # type: unset # range: unset ibpkeycon fe81:: 1 system:system:system:s0:c0.c1 # test 10: # subnet_prefix: unset # pkeys: 10, exact # user: unset # role: unset # type: unset # range: unset ibpkeycon ffff:: 0x10c-0x10e system:system:system:s0:c0.c1 # test 20: # subnet_prefix: unset # pkeys: unset # user: user20, exact # role: unset # type: unset # range: unset ibpkeycon ffff:: 20 user20:system:system:s0:c0.c1 # test 21: # subnet_prefix: unset # pkeys: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset ibpkeycon ffff:: 0x21a user21a:system:system:s0:c0.c1 ibpkeycon ffff:: 0x21b user21b:system:system:s0:c0.c1 ibpkeycon ffff:: 0x21c user21c:system:system:s0:c0.c1 # test 30: # subnet_prefix: unset # pkeys: unset # user: unset # role: role30_r, exact # type: unset # range: unset ibpkeycon ffff:: 30 system:role30_r:system:s0:c0.c1 # test 31: # subnet_prefix: unset # pkeys: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset ibpkeycon ffff:: 0x31a system:role31a_r:system:s0:c0.c1 ibpkeycon ffff:: 0x31b system:role31b_r:system:s0:c0.c1 ibpkeycon ffff:: 0x31c system:role31c_r:system:s0:c0.c1 # test 40: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: type40 # range: unset ibpkeycon ffff:: 40 system:system:type40:s0:c0.c1 # test 41: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: type41(b|c) # range: unset ibpkeycon ffff:: 0x41a system:system:type41a:s0:c0.c1 ibpkeycon ffff:: 0x41b system:system:type41b:s0:c0.c1 ibpkeycon ffff:: 0x41c system:system:type41c:s0:c0.c1 # test 50: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: equal ibpkeycon ffff:: 50 system:system:system:s0:c1 - s0:c0.c4 # test 51: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: overlap ibpkeycon ffff:: 51 system:system:system:s1:c1 - s1:c1.c3 # test 52: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: subset ibpkeycon ffff:: 52 system:system:system:s2:c1 - s2:c1.c3 # test 53: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: superset ibpkeycon ffff:: 53 system:system:system:s3:c1 - s3:c1.c3 # test 54: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: proper subset ibpkeycon ffff:: 54 system:system:system:s4:c1 - s4:c1.c3 # test 55: # subnet_prefix: unset # pkeys: unset # user: unset # role: unset # type: unset # range: proper superset ibpkeycon ffff:: 55 system:system:system:s5:c1 - s5:c1.c3 setools-4.4.0/tests/ibpkeyconquery.py000066400000000000000000000262561402045477700200210ustar00rootroot00000000000000# Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import IbpkeyconQuery from .policyrep.util import compile_policy class IbpkeyconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/ibpkeyconquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """ibpkeycon query with no criteria""" # query with no parameters gets all ibpkeycons. ibpkeycons = sorted(self.p.ibpkeycons()) q = IbpkeyconQuery(self.p) q_ibpkeycons = sorted(q.results()) self.assertListEqual(ibpkeycons, q_ibpkeycons) def test_001_subnet_mask(self): """Ibpkeycon query with subnet mask match.""" q = IbpkeyconQuery(self.p, subnet_prefix="fe81::") ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(1, 1)], ibpkeycons) def test_010_pkey_exact(self): """Ibpkeycon query with exact pkey match.""" q = IbpkeyconQuery(self.p, pkeys=(0x10c, 0x10e)) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(0x10c, 0x10e)], ibpkeycons) def test_020_user_exact(self): """ibpkeycon query with context user exact match""" q = IbpkeyconQuery(self.p, user="user20", user_regex=False) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(20, 20)], ibpkeycons) def test_021_user_regex(self): """ibpkeycon query with context user regex match""" q = IbpkeyconQuery(self.p, user="user21(a|b)", user_regex=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(0x21a, 0x21a), (0x21b, 0x21b)], ibpkeycons) def test_030_role_exact(self): """ibpkeycon query with context role exact match""" q = IbpkeyconQuery(self.p, role="role30_r", role_regex=False) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(30, 30)], ibpkeycons) def test_031_role_regex(self): """ibpkeycon query with context role regex match""" q = IbpkeyconQuery(self.p, role="role31(a|c)_r", role_regex=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(0x31a, 0x31a), (0x31c, 0x31c)], ibpkeycons) def test_040_type_exact(self): """ibpkeycon query with context type exact match""" q = IbpkeyconQuery(self.p, type_="type40", type_regex=False) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(40, 40)], ibpkeycons) def test_041_type_regex(self): """ibpkeycon query with context type regex match""" q = IbpkeyconQuery(self.p, type_="type41(b|c)", type_regex=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(0x41b, 0x41b), (0x41c, 0x41c)], ibpkeycons) def test_050_range_exact(self): """ibpkeycon query with context range exact match""" q = IbpkeyconQuery(self.p, range_="s0:c1 - s0:c0.c4") ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(50, 50)], ibpkeycons) def test_051_range_overlap1(self): """ibpkeycon query with context range overlap match (equal)""" q = IbpkeyconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(51, 51)], ibpkeycons) def test_051_range_overlap2(self): """ibpkeycon query with context range overlap match (subset)""" q = IbpkeyconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(51, 51)], ibpkeycons) def test_051_range_overlap3(self): """ibpkeycon query with context range overlap match (superset)""" q = IbpkeyconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(51, 51)], ibpkeycons) def test_051_range_overlap4(self): """ibpkeycon query with context range overlap match (overlap low level)""" q = IbpkeyconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(51, 51)], ibpkeycons) def test_051_range_overlap5(self): """ibpkeycon query with context range overlap match (overlap high level)""" q = IbpkeyconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(51, 51)], ibpkeycons) def test_052_range_subset1(self): """ibpkeycon query with context range subset match""" q = IbpkeyconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(52, 52)], ibpkeycons) def test_052_range_subset2(self): """ibpkeycon query with context range subset match (equal)""" q = IbpkeyconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(52, 52)], ibpkeycons) def test_053_range_superset1(self): """ibpkeycon query with context range superset match""" q = IbpkeyconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(53, 53)], ibpkeycons) def test_053_range_superset2(self): """ibpkeycon query with context range superset match (equal)""" q = IbpkeyconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(53, 53)], ibpkeycons) def test_054_range_proper_subset1(self): """ibpkeycon query with context range proper subset match""" q = IbpkeyconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(54, 54)], ibpkeycons) def test_054_range_proper_subset2(self): """ibpkeycon query with context range proper subset match (equal)""" q = IbpkeyconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([], ibpkeycons) def test_054_range_proper_subset3(self): """ibpkeycon query with context range proper subset match (equal low only)""" q = IbpkeyconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(54, 54)], ibpkeycons) def test_054_range_proper_subset4(self): """ibpkeycon query with context range proper subset match (equal high only)""" q = IbpkeyconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(54, 54)], ibpkeycons) def test_055_range_proper_superset1(self): """ibpkeycon query with context range proper superset match""" q = IbpkeyconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(55, 55)], ibpkeycons) def test_055_range_proper_superset2(self): """ibpkeycon query with context range proper superset match (equal)""" q = IbpkeyconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([], ibpkeycons) def test_055_range_proper_superset3(self): """ibpkeycon query with context range proper superset match (equal low)""" q = IbpkeyconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(55, 55)], ibpkeycons) def test_055_range_proper_superset4(self): """ibpkeycon query with context range proper superset match (equal high)""" q = IbpkeyconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ibpkeycons = sorted(n.pkeys for n in q.results()) self.assertListEqual([(55, 55)], ibpkeycons) def test_900_invalid_subnet_prefix(self): """Ibpkeycon query with invalid subnet prefix""" with self.assertRaises(ValueError): IbpkeyconQuery(self.p, subnet_prefix="INVALID") def test_910_invalid_pkey_negative(self): """Ibpkeycon query with negative pkey""" with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(-1, -1)) with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(1, -1)) with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(-1, 1)) def test_911_invalid_pkey_zero(self): """Ibpkeycon query with 0 pkey""" with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(0, 0)) def test_912_invalid_pkey_over_max(self): """Ibpkeycon query with pkey over maximum value""" with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(1, 0xfffff)) with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(0xfffff, 1)) with self.assertRaises(ValueError): IbpkeyconQuery(self.p, pkeys=(0xfffff, 0xfffff)) def test_913_invalid_pkey_not_a_number(self): """Ibpkeycon query with pkey is not a number""" with self.assertRaises(TypeError): IbpkeyconQuery(self.p, pkeys=(1, "INVALID")) with self.assertRaises(TypeError): IbpkeyconQuery(self.p, pkeys=("INVALID", 2)) def test_914_invalid_pkey_not_tuple(self): """Ibpkeycon query with pkey is not a tuple""" with self.assertRaises(TypeError): IbpkeyconQuery(self.p, pkeys=1) def test_915_invalid_pkey_wrong_tuple_length(self): """Ibpkeycon query with pkey is not correct tuple size""" with self.assertRaises(TypeError): IbpkeyconQuery(self.p, pkeys=(1,)) with self.assertRaises(TypeError): IbpkeyconQuery(self.p, pkeys=(1, 2, 3)) setools-4.4.0/tests/infoflow.conf000066400000000000000000000066341402045477700170660ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class file class process sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super } class infoflow3 { null } class file { execute entrypoint } class process { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Note: these tests should be to determine if the graph # is being constructed correctly. It is assumed that the # graph algorithms being used are correct, as they are # unit tested by the NetworkX project itself. # # # Max steps for all flows: 6 # # Graph if min weight is 8 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ # 1 -> 2-/ # # 3 5 -> 8 <-> 9 # # Graph if min weight is 3 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 5 -> 8 <-> 9 # # Graph if min weight is 1 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 -> 5 -> 8 <-> 9 # # # attribute allnodes; type node1, allnodes; type node2, allnodes; type node3, allnodes; type node4, allnodes; type node5, allnodes; type node6, allnodes; type node7, allnodes; type node8, allnodes; type node9, allnodes; # no infoflow allow allnodes allnodes:infoflow3 null; # 1->2 (10, 5) allow node1 node2:infoflow med_w; allow node2 node1:infoflow hi_r; # 1->3 (5, 1) allow node3 node1:infoflow { low_r med_r }; # 2->4 (10) allow node2 node4:infoflow hi_w; # 3->5 (1) allow node5 node3:infoflow low_r; # 4->6 (10) allow node4 node6:infoflow2 hi_w; # 6->5 (5) allow node5 node6:infoflow med_r; # 6->7 (10) allow node6 node7:infoflow hi_w; # 5->8 (10) allow node5 node8:infoflow2 hi_w; # 8 <-> 9 (10) allow node8 node9:infoflow2 super; # disconnected from the main graph # for testing the handling of no # paths. type disconnected1; type disconnected2; allow disconnected1 disconnected2:infoflow2 super; # not an infoflow: type disconnected3; auditallow node1 disconnected3:infoflow hi_w; # infoflow loop that should be ignored: allow disconnected3 self:infoflow hi_w; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/infoflow.py000066400000000000000000000462601402045477700165700ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import InfoFlowAnalysis from setools import TERuletype as TERT from setools.exception import InvalidType from setools.permmap import PermissionMap from setools.policyrep import Type from . import mixins from .policyrep.util import compile_policy # Note: the testing for having correct rules on every edge is only # performed once on the full graph, since it is assumed that NetworkX's # Digraph.subgraph() function correctly copies the edge attributes into # the subgraph. class InfoFlowAnalysisTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/infoflow.conf") cls.m = PermissionMap("tests/perm_map") cls.a = InfoFlowAnalysis(cls.p, cls.m) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_001_full_graph(self): """Information flow analysis full graph.""" self.a._build_graph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node3 = self.p.lookup_type("node3") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") nodes = set(self.a.G.nodes()) self.assertSetEqual(set([disconnected1, disconnected2, node1, node2, node3, node4, node5, node6, node7, node8, node9]), nodes) edges = set(self.a.G.out_edges()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node1, node3), (node2, node4), (node3, node5), (node4, node6), (node5, node8), (node6, node5), (node6, node7), (node8, node9), (node9, node8)]), edges) r = self.a.G.edges[disconnected1, disconnected2]["rules"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "disconnected1", "disconnected2", "infoflow2", set(["super"])) r = self.a.G.edges[disconnected2, disconnected1]["rules"] self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "disconnected1", "disconnected2", "infoflow2", set(["super"])) r = sorted(self.a.G.edges[node1, node2]["rules"]) self.assertEqual(len(r), 2) self.validate_rule(r[0], TERT.allow, "node1", "node2", "infoflow", set(["med_w"])) self.validate_rule(r[1], TERT.allow, "node2", "node1", "infoflow", set(["hi_r"])) r = sorted(self.a.G.edges[node1, node3]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node3", "node1", "infoflow", set(["low_r", "med_r"])) r = sorted(self.a.G.edges[node2, node4]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node2", "node4", "infoflow", set(["hi_w"])) r = sorted(self.a.G.edges[node3, node5]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node3", "infoflow", set(["low_r"])) r = sorted(self.a.G.edges[node4, node6]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node4", "node6", "infoflow2", set(["hi_w"])) r = sorted(self.a.G.edges[node5, node8]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node8", "infoflow2", set(["hi_w"])) r = sorted(self.a.G.edges[node6, node5]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node5", "node6", "infoflow", set(["med_r"])) r = sorted(self.a.G.edges[node6, node7]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node6", "node7", "infoflow", set(["hi_w"])) r = sorted(self.a.G.edges[node8, node9]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node8", "node9", "infoflow2", set(["super"])) r = sorted(self.a.G.edges[node9, node8]["rules"]) self.assertEqual(len(r), 1) self.validate_rule(r[0], TERT.allow, "node8", "node9", "infoflow2", set(["super"])) def test_100_minimum_3(self): """Information flow analysis with minimum weight 3.""" self.a.exclude = None self.a.min_weight = 3 self.a._build_subgraph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node3 = self.p.lookup_type("node3") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") # don't test nodes list, as disconnected nodes # are not removed by subgraph generation. we # assume NetworkX copies into the subgraph # correctly. edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node1, node3), (node2, node4), (node4, node6), (node5, node8), (node6, node5), (node6, node7), (node8, node9), (node9, node8)]), edges) def test_200_minimum_8(self): """Information flow analysis with minimum weight 8.""" self.a.exclude = None self.a.min_weight = 8 self.a._build_subgraph() disconnected1 = self.p.lookup_type("disconnected1") disconnected2 = self.p.lookup_type("disconnected2") node1 = self.p.lookup_type("node1") node2 = self.p.lookup_type("node2") node4 = self.p.lookup_type("node4") node5 = self.p.lookup_type("node5") node6 = self.p.lookup_type("node6") node7 = self.p.lookup_type("node7") node8 = self.p.lookup_type("node8") node9 = self.p.lookup_type("node9") # don't test nodes list, as disconnected nodes # are not removed by subgraph generation. we # assume NetworkX copies into the subgraph # correctly. edges = set(self.a.subG.out_edges()) self.assertSetEqual(set([(disconnected1, disconnected2), (disconnected2, disconnected1), (node1, node2), (node2, node4), (node4, node6), (node5, node8), (node6, node7), (node8, node9), (node9, node8)]), edges) def test_300_all_paths(self): """Information flow analysis: all paths output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node4", 3)) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_301_all_shortest_paths(self): """Information flow analysis: all shortest paths output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node4")) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_302_shortest_path(self): """Information flow analysis: shortest path output""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node4")) self.assertEqual(1, len(paths)) steps = list(paths[0]) self.assertEqual(2, len(steps)) step = steps[0] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node1") self.assertEqual(step.target, "node2") for r in steps[0].rules: self.assertEqual(TERT.allow, r.ruletype) step = steps[1] self.assertIsInstance(step.source, Type) self.assertIsInstance(step.target, Type) self.assertEqual(step.source, "node2") self.assertEqual(step.target, "node4") for r in step.rules: self.assertEqual(TERT.allow, r.ruletype) def test_303_infoflows_out(self): """Information flow analysis: flows out of a type""" self.a.exclude = None self.a.min_weight = 1 for flow in self.a.infoflows("node6"): self.assertIsInstance(flow.source, Type) self.assertIsInstance(flow.target, Type) self.assertEqual(flow.source, "node6") for r in flow.rules: self.assertEqual(TERT.allow, r.ruletype) def test_304_infoflows_in(self): """Information flow analysis: flows in to a type""" self.a.exclude = None self.a.min_weight = 1 for flow in self.a.infoflows("node8", out=False): self.assertIsInstance(flow.source, Type) self.assertIsInstance(flow.target, Type) self.assertEqual(flow.target, "node8") for r in flow.rules: self.assertEqual(TERT.allow, r.ruletype) def test_900_set_exclude_invalid_type(self): """Information flow analysis: set invalid excluded type.""" with self.assertRaises(InvalidType): self.a.exclude = ["node1", "invalid_type"] def test_901_set_small_min_weight(self): """Information flow analysis: set too small weight.""" with self.assertRaises(ValueError): self.a.min_weight = 0 with self.assertRaises(ValueError): self.a.min_weight = -3 def test_902_set_large_min_weight(self): """Information flow analysis: set too big weight.""" with self.assertRaises(ValueError): self.a.min_weight = 11 with self.assertRaises(ValueError): self.a.min_weight = 50 def test_910_all_paths_invalid_source(self): """Information flow analysis: all paths with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_paths("invalid_type", "node1")) def test_911_all_paths_invalid_target(self): """Information flow analysis: all paths with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_paths("node1", "invalid_type")) def test_912_all_paths_invalid_maxlen(self): """Information flow analysis: all paths with invalid max path length.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(ValueError): list(self.a.all_paths("node1", "node2", maxlen=-2)) def test_913_all_paths_source_excluded(self): """Information flow analysis: all paths with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_914_all_paths_target_excluded(self): """Information flow analysis: all paths with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.all_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_915_all_paths_source_disconnected(self): """Information flow analysis: all paths with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_916_all_paths_target_disconnected(self): """Information flow analysis: all paths with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_paths("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_920_shortest_path_invalid_source(self): """Information flow analysis: shortest path with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.shortest_path("invalid_type", "node1")) def test_921_shortest_path_invalid_target(self): """Information flow analysis: shortest path with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.shortest_path("node1", "invalid_type")) def test_922_shortest_path_source_excluded(self): """Information flow analysis: shortest path with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node2")) self.assertEqual(0, len(paths)) def test_923_shortest_path_target_excluded(self): """Information flow analysis: shortest path with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.shortest_path("node1", "node2")) self.assertEqual(0, len(paths)) def test_924_shortest_path_source_disconnected(self): """Information flow analysis: shortest path with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_925_shortest_path_target_disconnected(self): """Information flow analysis: shortest path with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.shortest_path("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_930_all_shortest_paths_invalid_source(self): """Information flow analysis: all shortest paths with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("invalid_type", "node1")) def test_931_all_shortest_paths_invalid_target(self): """Information flow analysis: all shortest paths with invalid target type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.all_shortest_paths("node1", "invalid_type")) def test_932_all_shortest_paths_source_excluded(self): """Information flow analysis: all shortest paths with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_933_all_shortest_paths_target_excluded(self): """Information flow analysis: all shortest paths with excluded target type.""" self.a.exclude = ["node2"] self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node1", "node2")) self.assertEqual(0, len(paths)) def test_934_all_shortest_paths_source_disconnected(self): """Information flow analysis: all shortest paths with disconnected source type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("disconnected1", "node2")) self.assertEqual(0, len(paths)) def test_935_all_shortest_paths_target_disconnected(self): """Information flow analysis: all shortest paths with disconnected target type.""" self.a.exclude = None self.a.min_weight = 1 paths = list(self.a.all_shortest_paths("node2", "disconnected1")) self.assertEqual(0, len(paths)) def test_940_infoflows_invalid_source(self): """Information flow analysis: infoflows with invalid source type.""" self.a.exclude = None self.a.min_weight = 1 with self.assertRaises(InvalidType): list(self.a.infoflows("invalid_type")) def test_941_infoflows_source_excluded(self): """Information flow analysis: infoflows with excluded source type.""" self.a.exclude = ["node1"] self.a.min_weight = 1 paths = list(self.a.infoflows("node1")) self.assertEqual(0, len(paths)) def test_942_infoflows_source_disconnected(self): """Information flow analysis: infoflows with disconnected source type.""" self.a.exclude = ["disconnected2"] self.a.min_weight = 1 paths = list(self.a.infoflows("disconnected1")) self.assertEqual(0, len(paths)) setools-4.4.0/tests/initsidquery.conf000066400000000000000000000113501402045477700177630ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 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 common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); ######################################### # # Initial SID query tests # # test 1: # name: kernel, exact # user: unset # role: unset # type: unset # range: unset sid kernel system:system:system:s0:c0.c4 # test 2: # name: (security|unlabeled), regex # user: unset # role: unset # type: unset # range: unset sid security system:system:system:s0:c0.c1 sid unlabeled system:system:system:s0:c2.c4 # test 10: # name: unset # user: user10, exact # role: unset # type: unset # range: unset sid fs user10:system:system:s0:c0.c1 # test 11: # name: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset sid file user11a:system:system:s0:c0.c1 sid file_labels user11b:system:system:s0:c0.c1 sid init user11c:system:system:s0:c0.c1 # test 20: # name: unset # user: unset # role: role20_r, exact # type: unset # range: unset sid any_socket system:role20_r:system:s0:c0.c1 # test 21: # name: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset sid port system:role21a_r:system:s0:c0.c1 sid netif system:role21b_r:system:s0:c0.c1 sid netmsg system:role21c_r:system:s0:c0.c1 # test 30: # name: unset # user: unset # role: unset # type: type30 # range: unset sid node system:system:type30:s0:c0.c1 # test 31: # name: unset # user: unset # role: unset # type: type31(b|c) # range: unset sid igmp_packet system:system:type31a:s0:c0.c1 sid icmp_socket system:system:type31b:s0:c0.c1 sid tcp_socket system:system:type31c:s0:c0.c1 # test 40: # name: unset # user: unset # role: unset # type: unset # range: equal sid sysctl_modprobe system:system:system:s0:c1 - s0:c0.c4 # test 41: # name: unset # user: unset # role: unset # type: unset # range: overlap sid sysctl system:system:system:s1:c1 - s1:c1.c3 # test 42: # name: unset # user: unset # role: unset # type: unset # range: subset sid sysctl_fs system:system:system:s2:c1 - s2:c1.c3 # test 43: # name: unset # user: unset # role: unset # type: unset # range: superset sid sysctl_kernel system:system:system:s3:c1 - s3:c1.c3 # test 44: # name: unset # user: unset # role: unset # type: unset # range: proper subset sid sysctl_net system:system:system:s4:c1 - s4:c1.c3 # test 45: # name: unset # user: unset # role: unset # type: unset # range: proper superset sid sysctl_net_unix system:system:system:s5:c1 - s5:c1.c3 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/initsidquery.py000066400000000000000000000217611402045477700174750ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import InitialSIDQuery from .policyrep.util import compile_policy class InitialSIDQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/initsidquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Initial SID query with no criteria""" # query with no parameters gets all SIDs. sids = sorted(self.p.initialsids()) q = InitialSIDQuery(self.p) q_sids = sorted(q.results()) self.assertListEqual(sids, q_sids) def test_001_name_exact(self): """Initial SID query with exact match""" q = InitialSIDQuery(self.p, name="kernel", name_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["kernel"], sids) def test_002_name_regex(self): """Initial SID query with regex match""" q = InitialSIDQuery(self.p, name="(security|unlabeled)", name_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["security", "unlabeled"], sids) def test_010_user_exact(self): """Initial SID query with context user exact match""" q = InitialSIDQuery(self.p, user="user10", user_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["fs"], sids) def test_011_user_regex(self): """Initial SID query with context user regex match""" q = InitialSIDQuery(self.p, user="user11(a|b)", user_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["file", "file_labels"], sids) def test_020_role_exact(self): """Initial SID query with context role exact match""" q = InitialSIDQuery(self.p, role="role20_r", role_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["any_socket"], sids) def test_021_role_regex(self): """Initial SID query with context role regex match""" q = InitialSIDQuery(self.p, role="role21(a|c)_r", role_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["netmsg", "port"], sids) def test_030_type_exact(self): """Initial SID query with context type exact match""" q = InitialSIDQuery(self.p, type_="type30", type_regex=False) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["node"], sids) def test_031_type_regex(self): """Initial SID query with context type regex match""" q = InitialSIDQuery(self.p, type_="type31(b|c)", type_regex=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["icmp_socket", "tcp_socket"], sids) def test_040_range_exact(self): """Initial SID query with context range exact match""" q = InitialSIDQuery(self.p, range_="s0:c1 - s0:c0.c4") sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_modprobe"], sids) def test_041_range_overlap1(self): """Initial SID query with context range overlap match (equal)""" q = InitialSIDQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl"], sids) def test_041_range_overlap2(self): """Initial SID query with context range overlap match (subset)""" q = InitialSIDQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl"], sids) def test_041_range_overlap3(self): """Initial SID query with context range overlap match (superset)""" q = InitialSIDQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl"], sids) def test_041_range_overlap4(self): """Initial SID query with context range overlap match (overlap low level)""" q = InitialSIDQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl"], sids) def test_041_range_overlap5(self): """Initial SID query with context range overlap match (overlap high level)""" q = InitialSIDQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl"], sids) def test_042_range_subset1(self): """Initial SID query with context range subset match""" q = InitialSIDQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_fs"], sids) def test_042_range_subset2(self): """Initial SID query with context range subset match (equal)""" q = InitialSIDQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_fs"], sids) def test_043_range_superset1(self): """Initial SID query with context range superset match""" q = InitialSIDQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_kernel"], sids) def test_043_range_superset2(self): """Initial SID query with context range superset match (equal)""" q = InitialSIDQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_kernel"], sids) def test_044_range_proper_subset1(self): """Initial SID query with context range proper subset match""" q = InitialSIDQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net"], sids) def test_044_range_proper_subset2(self): """Initial SID query with context range proper subset match (equal)""" q = InitialSIDQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual([], sids) def test_044_range_proper_subset3(self): """Initial SID query with context range proper subset match (equal low only)""" q = InitialSIDQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net"], sids) def test_044_range_proper_subset4(self): """Initial SID query with context range proper subset match (equal high only)""" q = InitialSIDQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net"], sids) def test_045_range_proper_superset1(self): """Initial SID query with context range proper superset match""" q = InitialSIDQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net_unix"], sids) def test_045_range_proper_superset2(self): """Initial SID query with context range proper superset match (equal)""" q = InitialSIDQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual([], sids) def test_045_range_proper_superset3(self): """Initial SID query with context range proper superset match (equal low)""" q = InitialSIDQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net_unix"], sids) def test_045_range_proper_superset4(self): """Initial SID query with context range proper superset match (equal high)""" q = InitialSIDQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) sids = sorted(str(s) for s in q.results()) self.assertListEqual(["sysctl_net_unix"], sids) setools-4.4.0/tests/invalid_perm_maps/000077500000000000000000000000001402045477700200545ustar00rootroot00000000000000setools-4.4.0/tests/invalid_perm_maps/bad-class-keyword000066400000000000000000000004261402045477700233140ustar00rootroot000000000000005 invalid infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/bad-perm-weight-high000066400000000000000000000004241402045477700236700ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 11 setools-4.4.0/tests/invalid_perm_maps/bad-perm-weight-low000066400000000000000000000004241402045477700235520ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w -1 setools-4.4.0/tests/invalid_perm_maps/bad-permcount000066400000000000000000000004321402045477700225360ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 INVALID null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/extra-class000066400000000000000000000004241402045477700222250ustar00rootroot000000000000004 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/extra-perms000066400000000000000000000004241402045477700222460ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/invalid-flowdir000066400000000000000000000004241402045477700230710ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r X 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/invalid-perm-weight000066400000000000000000000004311402045477700236510ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w INVALID setools-4.4.0/tests/invalid_perm_maps/negative-classcount000066400000000000000000000004251402045477700237560ustar00rootroot00000000000000-1 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/negative-permcount000066400000000000000000000004251402045477700236140ustar00rootroot000000000000005 class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 -1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/invalid_perm_maps/non-number-classcount000066400000000000000000000004321402045477700242320ustar00rootroot00000000000000invalid class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 class infoflow2 7 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 setools-4.4.0/tests/iomemconquery.conf000066400000000000000000000143231402045477700201310ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # mem addr: unset # user: unset # role: unset # type: unset # range: unset iomemcon 1 system:system:system:s0:c0.c1 # test 10: # mem addr: unset # user: user10, exact # role: unset # type: unset # range: unset iomemcon 10 user10:system:system:s0:c0.c1 # test 11: # mem addr: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset iomemcon 11 user11a:system:system:s0:c0.c1 iomemcon 11000 user11b:system:system:s0:c0.c1 iomemcon 11001 user11c:system:system:s0:c0.c1 # test 20: # mem addr: unset # user: unset # role: role20_r, exact # type: unset # range: unset iomemcon 20 system:role20_r:system:s0:c0.c1 # test 21: # mem addr: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset iomemcon 21 system:role21a_r:system:s0:c0.c1 iomemcon 21000 system:role21b_r:system:s0:c0.c1 iomemcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # mem addr: unset # user: unset # role: unset # type: type30 # range: unset iomemcon 30 system:system:type30:s0:c0.c1 # test 31: # mem addr: unset # user: unset # role: unset # type: type31(b|c) # range: unset iomemcon 31 system:system:type31a:s0:c0.c1 iomemcon 31000 system:system:type31b:s0:c0.c1 iomemcon 31001 system:system:type31c:s0:c0.c1 # test 40: # mem addr: unset # user: unset # role: unset # type: unset # range: equal iomemcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # mem addr: unset # user: unset # role: unset # type: unset # range: overlap iomemcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # mem addr: unset # user: unset # role: unset # type: unset # range: subset iomemcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # mem addr: unset # user: unset # role: unset # type: unset # range: superset iomemcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # mem addr: unset # user: unset # role: unset # type: unset # range: proper subset iomemcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # mem addr: unset # user: unset # role: unset # type: unset # range: proper superset iomemcon 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # mem addr: (50, 50) # user: unset # role: unset # type: unset # range: unset iomemcon 50 system:system:system:s0:c0.c1 # test 51: # mem addr: (50100, 50110) # user: unset # role: unset # type: unset # range: unset iomemcon 50100-50110 system:system:system:s0:c0.c1 # test 52: # mem addr: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset iomemcon 50200 system:system:system:s0:c0.c1 # test 53: # mem addr: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset iomemcon 50300-50310 system:system:system:s0:c0.c1 # test 54: # mem addr: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset iomemcon 50400 system:system:system:s0:c0.c1 # test 55: # mem addr: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset iomemcon 50500-50510 system:system:system:s0:c0.c1 # test 56: # mem addr: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset iomemcon 50601 system:system:system:s0:c0.c1 # test 57: # mem addr: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset iomemcon 50700-50710 system:system:system:s0:c0.c1 # test 58: # mem addr: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset iomemcon 50801 system:system:system:s0:c0.c1 # test 59: # mem addr: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset iomemcon 50901-50910 system:system:system:s0:c0.c1 # test 60: # mem addr: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60001 system:system:system:s0:c0.c1 # test 61: # mem addr: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60101-60110 system:system:system:s0:c0.c1 # test 62: # mem addr: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60200-60210 system:system:system:s0:c0.c1 # test 63: # mem addr: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60300-60310 system:system:system:s0:c0.c1 # test 64: # mem addr: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60400-60410 system:system:system:s0:c0.c1 # test 65: # mem addr: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset iomemcon 60501-60509 system:system:system:s0:c0.c1 setools-4.4.0/tests/iomemconquery.py000066400000000000000000000426261402045477700176430ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import IomemconQuery from .policyrep.util import compile_policy class IomemconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/iomemconquery.conf", xen=True) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Iomemcon query with no criteria""" # query with no parameters gets all addr. rules = sorted(self.p.iomemcons()) q = IomemconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Iomemcon query with context user exact match""" q = IomemconQuery(self.p, user="user10", user_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(10, 10)], addr) def test_011_user_regex(self): """Iomemcon query with context user regex match""" q = IomemconQuery(self.p, user="user11(a|b)", user_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], addr) def test_020_role_exact(self): """Iomemcon query with context role exact match""" q = IomemconQuery(self.p, role="role20_r", role_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(20, 20)], addr) def test_021_role_regex(self): """Iomemcon query with context role regex match""" q = IomemconQuery(self.p, role="role21(a|c)_r", role_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], addr) def test_030_type_exact(self): """Iomemcon query with context type exact match""" q = IomemconQuery(self.p, type_="type30", type_regex=False) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(30, 30)], addr) def test_031_type_regex(self): """Iomemcon query with context type regex match""" q = IomemconQuery(self.p, type_="type31(b|c)", type_regex=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], addr) def test_040_range_exact(self): """Iomemcon query with context range exact match""" q = IomemconQuery(self.p, range_="s0:c1 - s0:c0.c4") addr = sorted(p.addr for p in q.results()) self.assertListEqual([(40, 40)], addr) def test_041_range_overlap1(self): """Iomemcon query with context range overlap match (equal)""" q = IomemconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap2(self): """Iomemcon query with context range overlap match (subset)""" q = IomemconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap3(self): """Iomemcon query with context range overlap match (superset)""" q = IomemconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap4(self): """Iomemcon query with context range overlap match (overlap low level)""" q = IomemconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_041_range_overlap5(self): """Iomemcon query with context range overlap match (overlap high level)""" q = IomemconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(41, 41)], addr) def test_042_range_subset1(self): """Iomemcon query with context range subset match""" q = IomemconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(42, 42)], addr) def test_042_range_subset2(self): """Iomemcon query with context range subset match (equal)""" q = IomemconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(42, 42)], addr) def test_043_range_superset1(self): """Iomemcon query with context range superset match""" q = IomemconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(43, 43)], addr) def test_043_range_superset2(self): """Iomemcon query with context range superset match (equal)""" q = IomemconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(43, 43)], addr) def test_044_range_proper_subset1(self): """Iomemcon query with context range proper subset match""" q = IomemconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_044_range_proper_subset2(self): """Iomemcon query with context range proper subset match (equal)""" q = IomemconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_044_range_proper_subset3(self): """Iomemcon query with context range proper subset match (equal low only)""" q = IomemconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_044_range_proper_subset4(self): """Iomemcon query with context range proper subset match (equal high only)""" q = IomemconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(44, 44)], addr) def test_045_range_proper_superset1(self): """Iomemcon query with context range proper superset match""" q = IomemconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_045_range_proper_superset2(self): """Iomemcon query with context range proper superset match (equal)""" q = IomemconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_045_range_proper_superset3(self): """Iomemcon query with context range proper superset match (equal low)""" q = IomemconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_045_range_proper_superset4(self): """Iomemcon query with context range proper superset match (equal high)""" q = IomemconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(45, 45)], addr) def test_050_single_equal(self): """Iomemcon query with single mem addr exact match""" q = IomemconQuery(self.p, addr=(50, 50)) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50, 50)], addr) def test_051_range_equal(self): """Iomemcon query with mem addr range exact match""" q = IomemconQuery(self.p, addr=(50100, 50110)) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50100, 50110)], addr) def test_052_single_subset(self): """Iomemcon query with single mem addr subset""" q = IomemconQuery(self.p, addr=(50200, 50200), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50200, 50200)], addr) def test_053_range_subset(self): """Iomemcon query with range subset""" q = IomemconQuery(self.p, addr=(50301, 50309), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50300, 50310)], addr) def test_053_range_subset_edge1(self): """Iomemcon query with range subset, equal edge case""" q = IomemconQuery(self.p, addr=(50300, 50310), addr_subset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50300, 50310)], addr) def test_054_single_proper_subset(self): """Iomemcon query with single mem addr proper subset""" q = IomemconQuery( self.p, addr=(50400, 50400), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_055_range_proper_subset(self): """Iomemcon query with range proper subset""" q = IomemconQuery( self.p, addr=(50501, 50509), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_055_range_proper_subset_edge1(self): """Iomemcon query with range proper subset, equal edge case""" q = IomemconQuery( self.p, addr=(50500, 50510), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_055_range_proper_subset_edge2(self): """Iomemcon query with range proper subset, low equal edge case""" q = IomemconQuery( self.p, addr=(50500, 50509), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_055_range_proper_subset_edge3(self): """Iomemcon query with range proper subset, high equal edge case""" q = IomemconQuery( self.p, addr=(50501, 50510), addr_subset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50500, 50510)], addr) def test_056_single_superset(self): """Iomemcon query with single mem addr superset""" q = IomemconQuery(self.p, addr=(50600, 50602), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50601, 50601)], addr) def test_056_single_superset_edge1(self): """Iomemcon query with single mem addr superset, equal edge case""" q = IomemconQuery(self.p, addr=(50601, 50601), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50601, 50601)], addr) def test_057_range_superset(self): """Iomemcon query with range superset""" q = IomemconQuery(self.p, addr=(50700, 50711), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50700, 50710)], addr) def test_057_range_superset_edge1(self): """Iomemcon query with range superset, equal edge case""" q = IomemconQuery(self.p, addr=(50700, 50710), addr_superset=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50700, 50710)], addr) def test_058_single_proper_superset(self): """Iomemcon query with single mem addr proper superset""" q = IomemconQuery( self.p, addr=(50800, 50802), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_058_single_proper_superset_edge1(self): """Iomemcon query with single mem addr proper superset, equal edge case""" q = IomemconQuery( self.p, addr=(50801, 50801), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_058_single_proper_superset_edge2(self): """Iomemcon query with single mem addr proper superset, low equal edge case""" q = IomemconQuery( self.p, addr=(50801, 50802), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_058_single_proper_superset_edge3(self): """Iomemcon query with single mem addr proper superset, high equal edge case""" q = IomemconQuery( self.p, addr=(50800, 50801), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50801, 50801)], addr) def test_059_range_proper_superset(self): """Iomemcon query with range proper superset""" q = IomemconQuery( self.p, addr=(50900, 50911), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_059_range_proper_superset_edge1(self): """Iomemcon query with range proper superset, equal edge case""" q = IomemconQuery( self.p, addr=(50901, 50910), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([], addr) def test_059_range_proper_superset_edge2(self): """Iomemcon query with range proper superset, equal high mem addr edge case""" q = IomemconQuery( self.p, addr=(50900, 50910), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_059_range_proper_superset_edge3(self): """Iomemcon query with range proper superset, equal low mem addr edge case""" q = IomemconQuery( self.p, addr=(50901, 50911), addr_superset=True, addr_proper=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(50901, 50910)], addr) def test_060_single_overlap(self): """Iomemcon query with single overlap""" q = IomemconQuery(self.p, addr=(60001, 60001), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge1(self): """Iomemcon query with single overlap, range match low""" q = IomemconQuery(self.p, addr=(60001, 60002), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge2(self): """Iomemcon query with single overlap, range match high""" q = IomemconQuery(self.p, addr=(60000, 60001), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_060_single_overlap_edge3(self): """Iomemcon query with single overlap, range match proper superset""" q = IomemconQuery(self.p, addr=(60000, 60002), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60001, 60001)], addr) def test_061_range_overlap_low_half(self): """Iomemcon query with range overlap, low half match""" q = IomemconQuery(self.p, addr=(60100, 60105), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60101, 60110)], addr) def test_062_range_overlap_high_half(self): """Iomemcon query with range overlap, high half match""" q = IomemconQuery(self.p, addr=(60205, 60211), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60200, 60210)], addr) def test_063_range_overlap_middle(self): """Iomemcon query with range overlap, middle match""" q = IomemconQuery(self.p, addr=(60305, 60308), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60300, 60310)], addr) def test_064_range_overlap_equal(self): """Iomemcon query with range overlap, equal match""" q = IomemconQuery(self.p, addr=(60400, 60410), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60400, 60410)], addr) def test_065_range_overlap_superset(self): """Iomemcon query with range overlap, superset match""" q = IomemconQuery(self.p, addr=(60500, 60510), addr_overlap=True) addr = sorted(p.addr for p in q.results()) self.assertListEqual([(60501, 60509)], addr) setools-4.4.0/tests/ioportconquery.conf000066400000000000000000000142371402045477700203430ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # ports: unset # user: unset # role: unset # type: unset # range: unset ioportcon 1 system:system:system:s0:c0.c1 # test 10: # ports: unset # user: user10, exact # role: unset # type: unset # range: unset ioportcon 10 user10:system:system:s0:c0.c1 # test 11: # ports: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset ioportcon 11 user11a:system:system:s0:c0.c1 ioportcon 11000 user11b:system:system:s0:c0.c1 ioportcon 11001 user11c:system:system:s0:c0.c1 # test 20: # ports: unset # user: unset # role: role20_r, exact # type: unset # range: unset ioportcon 20 system:role20_r:system:s0:c0.c1 # test 21: # ports: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset ioportcon 21 system:role21a_r:system:s0:c0.c1 ioportcon 21000 system:role21b_r:system:s0:c0.c1 ioportcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # ports: unset # user: unset # role: unset # type: type30 # range: unset ioportcon 30 system:system:type30:s0:c0.c1 # test 31: # ports: unset # user: unset # role: unset # type: type31(b|c) # range: unset ioportcon 31 system:system:type31a:s0:c0.c1 ioportcon 31000 system:system:type31b:s0:c0.c1 ioportcon 31001 system:system:type31c:s0:c0.c1 # test 40: # ports: unset # user: unset # role: unset # type: unset # range: equal ioportcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # ports: unset # user: unset # role: unset # type: unset # range: overlap ioportcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # ports: unset # user: unset # role: unset # type: unset # range: subset ioportcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # ports: unset # user: unset # role: unset # type: unset # range: superset ioportcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # ports: unset # user: unset # role: unset # type: unset # range: proper subset ioportcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # ports: unset # user: unset # role: unset # type: unset # range: proper superset ioportcon 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # ports: (50, 50) # user: unset # role: unset # type: unset # range: unset ioportcon 50 system:system:system:s0:c0.c1 # test 51: # ports: (50100, 50110) # user: unset # role: unset # type: unset # range: unset ioportcon 50100-50110 system:system:system:s0:c0.c1 # test 52: # ports: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset ioportcon 50200 system:system:system:s0:c0.c1 # test 53: # ports: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset ioportcon 50300-50310 system:system:system:s0:c0.c1 # test 54: # ports: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset ioportcon 50400 system:system:system:s0:c0.c1 # test 55: # ports: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset ioportcon 50500-50510 system:system:system:s0:c0.c1 # test 56: # ports: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset ioportcon 50601 system:system:system:s0:c0.c1 # test 57: # ports: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset ioportcon 50700-50710 system:system:system:s0:c0.c1 # test 58: # ports: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset ioportcon 50801 system:system:system:s0:c0.c1 # test 59: # ports: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset ioportcon 50901-50910 system:system:system:s0:c0.c1 # test 60: # ports: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60001 system:system:system:s0:c0.c1 # test 61: # ports: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60101-60110 system:system:system:s0:c0.c1 # test 62: # ports: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60200-60210 system:system:system:s0:c0.c1 # test 63: # ports: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60300-60310 system:system:system:s0:c0.c1 # test 64: # ports: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60400-60410 system:system:system:s0:c0.c1 # test 65: # ports: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset ioportcon 60501-60509 system:system:system:s0:c0.c1 setools-4.4.0/tests/ioportconquery.py000066400000000000000000000432221402045477700200420ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import IoportconQuery from .policyrep.util import compile_policy class IoportconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/ioportconquery.conf", xen=True) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Ioportcon query with no criteria""" # query with no parameters gets all ports. rules = sorted(self.p.ioportcons()) q = IoportconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Portcon query with context user exact match""" q = IoportconQuery(self.p, user="user10", user_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(10, 10)], ports) def test_011_user_regex(self): """Portcon query with context user regex match""" q = IoportconQuery(self.p, user="user11(a|b)", user_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], ports) def test_020_role_exact(self): """Portcon query with context role exact match""" q = IoportconQuery(self.p, role="role20_r", role_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(20, 20)], ports) def test_021_role_regex(self): """Portcon query with context role regex match""" q = IoportconQuery(self.p, role="role21(a|c)_r", role_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], ports) def test_030_type_exact(self): """Portcon query with context type exact match""" q = IoportconQuery(self.p, type_="type30", type_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(30, 30)], ports) def test_031_type_regex(self): """Portcon query with context type regex match""" q = IoportconQuery(self.p, type_="type31(b|c)", type_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], ports) def test_040_range_exact(self): """Portcon query with context range exact match""" q = IoportconQuery(self.p, range_="s0:c1 - s0:c0.c4") ports = sorted(p.ports for p in q.results()) self.assertListEqual([(40, 40)], ports) def test_041_range_overlap1(self): """Portcon query with context range overlap match (equal)""" q = IoportconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap2(self): """Portcon query with context range overlap match (subset)""" q = IoportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap3(self): """Portcon query with context range overlap match (superset)""" q = IoportconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap4(self): """Portcon query with context range overlap match (overlap low level)""" q = IoportconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap5(self): """Portcon query with context range overlap match (overlap high level)""" q = IoportconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_042_range_subset1(self): """Portcon query with context range subset match""" q = IoportconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_042_range_subset2(self): """Portcon query with context range subset match (equal)""" q = IoportconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_043_range_superset1(self): """Portcon query with context range superset match""" q = IoportconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_043_range_superset2(self): """Portcon query with context range superset match (equal)""" q = IoportconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_044_range_proper_subset1(self): """Portcon query with context range proper subset match""" q = IoportconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset2(self): """Portcon query with context range proper subset match (equal)""" q = IoportconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_044_range_proper_subset3(self): """Portcon query with context range proper subset match (equal low only)""" q = IoportconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset4(self): """Portcon query with context range proper subset match (equal high only)""" q = IoportconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_045_range_proper_superset1(self): """Portcon query with context range proper superset match""" q = IoportconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset2(self): """Portcon query with context range proper superset match (equal)""" q = IoportconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_045_range_proper_superset3(self): """Portcon query with context range proper superset match (equal low)""" q = IoportconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset4(self): """Portcon query with context range proper superset match (equal high)""" q = IoportconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_050_single_equal(self): """Portcon query with single port exact match""" q = IoportconQuery(self.p, ports=(50, 50)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50, 50)], ports) def test_051_range_equal(self): """Portcon query with port range exact match""" q = IoportconQuery(self.p, ports=(50100, 50110)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50100, 50110)], ports) def test_052_single_subset(self): """Portcon query with single port subset""" q = IoportconQuery(self.p, ports=(50200, 50200), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50200, 50200)], ports) def test_053_range_subset(self): """Portcon query with range subset""" q = IoportconQuery(self.p, ports=(50301, 50309), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_053_range_subset_edge1(self): """Portcon query with range subset, equal edge case""" q = IoportconQuery(self.p, ports=(50300, 50310), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_054_single_proper_subset(self): """Portcon query with single port proper subset""" q = IoportconQuery( self.p, ports=(50400, 50400), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset(self): """Portcon query with range proper subset""" q = IoportconQuery( self.p, ports=(50501, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge1(self): """Portcon query with range proper subset, equal edge case""" q = IoportconQuery( self.p, ports=(50500, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset_edge2(self): """Portcon query with range proper subset, low equal edge case""" q = IoportconQuery( self.p, ports=(50500, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge3(self): """Portcon query with range proper subset, high equal edge case""" q = IoportconQuery( self.p, ports=(50501, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_056_single_superset(self): """Portcon query with single port superset""" q = IoportconQuery(self.p, ports=(50600, 50602), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_056_single_superset_edge1(self): """Portcon query with single port superset, equal edge case""" q = IoportconQuery(self.p, ports=(50601, 50601), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_057_range_superset(self): """Portcon query with range superset""" q = IoportconQuery(self.p, ports=(50700, 50711), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_057_range_superset_edge1(self): """Portcon query with range superset, equal edge case""" q = IoportconQuery(self.p, ports=(50700, 50710), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_058_single_proper_superset(self): """Portcon query with single port proper superset""" q = IoportconQuery( self.p, ports=(50800, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge1(self): """Portcon query with single port proper superset, equal edge case""" q = IoportconQuery( self.p, ports=(50801, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_058_single_proper_superset_edge2(self): """Portcon query with single port proper superset, low equal edge case""" q = IoportconQuery( self.p, ports=(50801, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge3(self): """Portcon query with single port proper superset, high equal edge case""" q = IoportconQuery( self.p, ports=(50800, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_059_range_proper_superset(self): """Portcon query with range proper superset""" q = IoportconQuery( self.p, ports=(50900, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge1(self): """Portcon query with range proper superset, equal edge case""" q = IoportconQuery( self.p, ports=(50901, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_059_range_proper_superset_edge2(self): """Portcon query with range proper superset, equal high port edge case""" q = IoportconQuery( self.p, ports=(50900, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge3(self): """Portcon query with range proper superset, equal low port edge case""" q = IoportconQuery( self.p, ports=(50901, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_060_single_overlap(self): """Portcon query with single overlap""" q = IoportconQuery(self.p, ports=(60001, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge1(self): """Portcon query with single overlap, range match low""" q = IoportconQuery(self.p, ports=(60001, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge2(self): """Portcon query with single overlap, range match high""" q = IoportconQuery(self.p, ports=(60000, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge3(self): """Portcon query with single overlap, range match proper superset""" q = IoportconQuery(self.p, ports=(60000, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_061_range_overlap_low_half(self): """Portcon query with range overlap, low half match""" q = IoportconQuery(self.p, ports=(60100, 60105), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60101, 60110)], ports) def test_062_range_overlap_high_half(self): """Portcon query with range overlap, high half match""" q = IoportconQuery(self.p, ports=(60205, 60211), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60200, 60210)], ports) def test_063_range_overlap_middle(self): """Portcon query with range overlap, middle match""" q = IoportconQuery(self.p, ports=(60305, 60308), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60300, 60310)], ports) def test_064_range_overlap_equal(self): """Portcon query with range overlap, equal match""" q = IoportconQuery(self.p, ports=(60400, 60410), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60400, 60410)], ports) def test_065_range_overlap_superset(self): """Portcon query with range overlap, superset match""" q = IoportconQuery(self.p, ports=(60500, 60510), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60501, 60509)], ports) setools-4.4.0/tests/mixins.py000066400000000000000000000037461402045477700162560ustar00rootroot00000000000000"""Unit test mixin classes.""" # Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # pylint: disable=too-few-public-methods import unittest from setools.exception import RuleNotConditional, RuleUseError class ValidateRule(unittest.TestCase): """Mixin for validating policy rules.""" def validate_rule(self, rule, ruletype, source, target, tclass, last_item, cond=None, cond_block=None, xperm=None): """Validate a rule.""" self.assertEqual(ruletype, rule.ruletype) self.assertEqual(source, rule.source) self.assertEqual(target, rule.target) self.assertEqual(tclass, rule.tclass) try: # This is the common case. self.assertSetEqual(last_item, rule.perms) except (AttributeError, RuleUseError): self.assertEqual(last_item, rule.default) if cond: self.assertEqual(cond, rule.conditional) else: self.assertRaises(RuleNotConditional, getattr, rule, "conditional") if cond_block is not None: self.assertEqual(cond_block, rule.conditional_block) if xperm: self.assertEqual(xperm, rule.xperm_type) self.assertTrue(rule.extended) else: self.assertRaises(AttributeError, getattr, rule, "xperm_type") self.assertFalse(rule.extended) setools-4.4.0/tests/mlsrulequery.conf000066400000000000000000000163141402045477700200100ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s46; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s46 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c0.c4; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s46:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # MLS Rule Query # # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # range: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; range_transition test1a test1t:infoflow s0; range_transition test1FAIL test1FAIL:infoflow s1; # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # range: unset attribute test2a; type test2s, test2a; type test2t; range_transition test2a test2t:infoflow s0; #range_transition test2s test2t:infoflow s1; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # range: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; range_transition test3s test3t:infoflow s1; range_transition test3aS test3t:infoflow2 s2; range_transition test3b test3t:infoflow s3; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # range: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; range_transition test4a1 test4a1:infoflow s1; range_transition test4a2 test4a2:infoflow2 s2; range_transition test4FAIL test4FAIL:infoflow s3; # test 5 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with source criteria that is an attribute, indirect match # # ruletype: unset # source: test5b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test5a; attribute test5b; type test5t1, test5a, test5b; type test5t2, test5b; type test5target; range_transition test5t1 test5target:infoflow s1; range_transition test5t2 test5target:infoflow7 s2; # test 10 # ruletype: unset # source: unset # target: test10a, direct, no regex # class: unset # range: unset attribute test10a; type test10s; type test10t, test10a; range_transition test10s test10a:infoflow s0; range_transition test10s test10t:infoflow2 s1; # test 11 # ruletype: unset # source: unset # target: test11t, indirect, no regex # class: unset # range: unset attribute test11a; type test11s; type test11t, test11a; range_transition test11s test11a:infoflow s0; range_transition test11s test11t:infoflow2 s1; # test 12 # ruletype: unset # source: unset # target: test12a.*, direct, regex # class: unset # range: unset attribute test12aPASS; attribute test12b; type test12s; type test12t, test12aPASS; type test12aFAIL, test12b; range_transition test12s test12t:infoflow s0; range_transition test12s test12aPASS:infoflow2 s1; range_transition test12s test12b:infoflow s2; # test 13 # ruletype: unset # source: unset # target: test13(s|t), indirect, regex # class: unset # range: unset attribute test13a1; attribute test13a2; type test13s1, test13a1; type test13t1, test13a2; type test13FAIL; range_transition test13a1 test13a1:infoflow s0; range_transition test13a2 test13a2:infoflow s1; range_transition test13FAIL test13FAIL:infoflow s2; # test 14 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with target criteria that is an attribute, indirect match # # ruletype: unset # source: test14b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test14a; attribute test14b; type test14t1, test14a, test14b; type test14t2, test14b; type test14source; range_transition test14source test14t1:infoflow s1; range_transition test14source test14t2:infoflow7 s2; # test 20 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # range: unset type test20; range_transition test20 test20:infoflow s0; range_transition test20 test20:infoflow7 s1; # test 21 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # range: unset type test21; range_transition test21 test21:infoflow s0; range_transition test21 test21:infoflow4 s1; range_transition test21 test21:infoflow3 s2; # test 22 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # range: unset type test22; range_transition test22 test22:infoflow s0; range_transition test22 test22:infoflow5 s1; range_transition test22 test22:infoflow6 s2; # test 40: # ruletype: unset # source: unset # target: unset # class: unset # range: equal type test40; range_transition test40 test40:infoflow s40:c1 - s40:c0.c4; # test 41: # ruletype: unset # source: unset # target: unset # class: unset # range: overlap type test41; range_transition test41 test41:infoflow s41:c1 - s41:c1.c3; # test 42: # ruletype: unset # source: unset # target: unset # class: unset # range: subset type test42; range_transition test42 test42:infoflow s42:c1 - s42:c1.c3; # test 43: # ruletype: unset # source: unset # target: unset # class: unset # range: superset type test43; range_transition test43 test43:infoflow s43:c1 - s43:c1.c3; # test 44: # ruletype: unset # source: unset # target: unset # class: unset # range: proper subset type test44; range_transition test44 test44:infoflow s44:c1 - s44:c1.c3; # test 45: # ruletype: unset # source: unset # target: unset # class: unset # range: proper superset type test45; range_transition test45 test45:infoflow s45:c1 - s45:c1.c3; ################################################################################ #users user system roles system level s0 range s0 - s46:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/mlsrulequery.py000066400000000000000000000315161402045477700175140ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import MLSRuleQuery from setools import MLSRuletype as RT from . import mixins from .policyrep.util import compile_policy # Note: the test policy has been written assuming range_transition # statements could have attributes. However, range_transition # statements are always expanded, so the below unit tests # have been adjusted to this fact (hence a "FAIL" in one of the # expected type names) class MLSRuleQueryTest(mixins.ValidateRule, unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/mlsrulequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """MLS rule query with no criteria.""" # query with no parameters gets all MLS rules. rules = sorted(self.p.mlsrules()) q = MLSRuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """MLS rule query with exact, direct, source match.""" q = MLSRuleQuery( self.p, source="test1s", source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test1s", "test1t", "infoflow", "s0") def test_003_source_direct_regex(self): """MLS rule query with regex, direct, source match.""" q = MLSRuleQuery( self.p, source="test3(s|aS)", source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test3s", "test3t", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test3s", "test3t", "infoflow2", "s2") def test_005_issue111(self): """MLS rule query with attribute source criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = MLSRuleQuery(self.p, source="test5b", source_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test5t1", "test5target", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test5t2", "test5target", "infoflow7", "s2") def test_010_target_direct(self): """MLS rule query with exact, direct, target match.""" q = MLSRuleQuery( self.p, target="test10t", target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test10s", "test10t", "infoflow", "s0") self.validate_rule(r[1], RT.range_transition, "test10s", "test10t", "infoflow2", "s1") def test_012_target_direct_regex(self): """MLS rule query with regex, direct, target match.""" q = MLSRuleQuery( self.p, target="test12a.*", target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test12s", "test12aFAIL", "infoflow", "s2") def test_014_issue111(self): """MLS rule query with attribute target criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = MLSRuleQuery(self.p, target="test14b", target_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test14source", "test14t1", "infoflow", "s1") self.validate_rule(r[1], RT.range_transition, "test14source", "test14t2", "infoflow7", "s2") @unittest.skip("Setting tclass to a string is no longer supported.") def test_020_class(self): """MLS rule query with exact object class match.""" q = MLSRuleQuery(self.p, tclass="infoflow7", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test20", "test20", "infoflow7", "s1") def test_021_class_list(self): """MLS rule query with object class list match.""" q = MLSRuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test21", "test21", "infoflow3", "s2") self.validate_rule(r[1], RT.range_transition, "test21", "test21", "infoflow4", "s1") def test_022_class_regex(self): """MLS rule query with object class regex match.""" q = MLSRuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RT.range_transition, "test22", "test22", "infoflow5", "s1") self.validate_rule(r[1], RT.range_transition, "test22", "test22", "infoflow6", "s2") def test_040_range_exact(self): """MLS rule query with context range exact match""" q = MLSRuleQuery(self.p, default="s40:c1 - s40:c0.c4") r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test40", "test40", "infoflow", "s40:c1 - s40:c0.c4") def test_041_range_overlap1(self): """MLS rule query with context range overlap match (equal)""" q = MLSRuleQuery(self.p, default="s41:c1 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap2(self): """MLS rule query with context range overlap match (subset)""" q = MLSRuleQuery(self.p, default="s41:c1,c2 - s41:c0.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap3(self): """MLS rule query with context range overlap match (superset)""" q = MLSRuleQuery(self.p, default="s41 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap4(self): """MLS rule query with context range overlap match (overlap low level)""" q = MLSRuleQuery(self.p, default="s41 - s41:c1,c2", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_041_range_overlap5(self): """MLS rule query with context range overlap match (overlap high level)""" q = MLSRuleQuery(self.p, default="s41:c1,c2 - s41:c0.c4", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test41", "test41", "infoflow", "s41:c1 - s41:c1.c3") def test_042_range_subset1(self): """MLS rule query with context range subset match""" q = MLSRuleQuery(self.p, default="s42:c1,c2 - s42:c0.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test42", "test42", "infoflow", "s42:c1 - s42:c1.c3") def test_042_range_subset2(self): """MLS rule query with context range subset match (equal)""" q = MLSRuleQuery(self.p, default="s42:c1 - s42:c1.c3", default_overlap=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test42", "test42", "infoflow", "s42:c1 - s42:c1.c3") def test_043_range_superset1(self): """MLS rule query with context range superset match""" q = MLSRuleQuery(self.p, default="s43 - s43:c0.c4", default_superset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test43", "test43", "infoflow", "s43:c1 - s43:c1.c3") def test_043_range_superset2(self): """MLS rule query with context range superset match (equal)""" q = MLSRuleQuery(self.p, default="s43:c1 - s43:c1.c3", default_superset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test43", "test43", "infoflow", "s43:c1 - s43:c1.c3") def test_044_range_proper_subset1(self): """MLS rule query with context range proper subset match""" q = MLSRuleQuery(self.p, default="s44:c1,c2", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_044_range_proper_subset2(self): """MLS rule query with context range proper subset match (equal)""" q = MLSRuleQuery(self.p, default="s44:c1 - s44:c1.c3", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 0) def test_044_range_proper_subset3(self): """MLS rule query with context range proper subset match (equal low only)""" q = MLSRuleQuery(self.p, default="s44:c1 - s44:c1.c2", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_044_range_proper_subset4(self): """MLS rule query with context range proper subset match (equal high only)""" q = MLSRuleQuery(self.p, default="s44:c1,c2 - s44:c1.c3", default_subset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test44", "test44", "infoflow", "s44:c1 - s44:c1.c3") def test_045_range_proper_superset1(self): """MLS rule query with context range proper superset match""" q = MLSRuleQuery(self.p, default="s45 - s45:c0.c4", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_045_range_proper_superset2(self): """MLS rule query with context range proper superset match (equal)""" q = MLSRuleQuery(self.p, default="s45:c1 - s45:c1.c3", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 0) def test_045_range_proper_superset3(self): """MLS rule query with context range proper superset match (equal low)""" q = MLSRuleQuery(self.p, default="s45:c1 - s45:c1.c4", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_045_range_proper_superset4(self): """MLS rule query with context range proper superset match (equal high)""" q = MLSRuleQuery(self.p, default="s45 - s45:c1.c3", default_superset=True, default_proper=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RT.range_transition, "test45", "test45", "infoflow", "s45:c1 - s45:c1.c3") def test_900_invalid_ruletype(self): """MLS rule query with invalid rule type.""" with self.assertRaises(KeyError): q = MLSRuleQuery(self.p, ruletype=["type_transition"]) setools-4.4.0/tests/netifconquery.conf000066400000000000000000000120311402045477700201220ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 # test 1: # name: test1, exact # user: unset # role: unset # type: unset # range: unset netifcon test1 system:system:system:s0:c0.c4 system:object_r:system:s0 # test 2: # name: test2(a|b), regex # user: unset # role: unset # type: unset # range: unset netifcon test2a system:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test2b system:system:system:s0:c2.c4 system:object_r:system:s0 # test 10: # name: unset # user: user10, exact # role: unset # type: unset # range: unset netifcon test10 user10:system:system:s0:c0.c1 system:object_r:system:s0 # test 11: # name: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset netifcon test11a user11a:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test11b user11b:system:system:s0:c0.c1 system:object_r:system:s0 netifcon test11c user11c:system:system:s0:c0.c1 system:object_r:system:s0 # test 20: # name: unset # user: unset # role: role20_r, exact # type: unset # range: unset netifcon test20 system:role20_r:system:s0:c0.c1 system:object_r:system:s0 # test 21: # name: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset netifcon test21a system:role21a_r:system:s0:c0.c1 system:object_r:system:s0 netifcon test21b system:role21b_r:system:s0:c0.c1 system:object_r:system:s0 netifcon test21c system:role21c_r:system:s0:c0.c1 system:object_r:system:s0 # test 30: # name: unset # user: unset # role: unset # type: type30 # range: unset netifcon test30 system:system:type30:s0:c0.c1 system:object_r:system:s0 # test 31: # name: unset # user: unset # role: unset # type: type31(b|c) # range: unset netifcon test31a system:system:type31a:s0:c0.c1 system:object_r:system:s0 netifcon test31b system:system:type31b:s0:c0.c1 system:object_r:system:s0 netifcon test31c system:system:type31c:s0:c0.c1 system:object_r:system:s0 # test 40: # name: unset # user: unset # role: unset # type: unset # range: equal netifcon test40 system:system:system:s0:c1 - s0:c0.c4 system:object_r:system:s0 # test 41: # name: unset # user: unset # role: unset # type: unset # range: overlap netifcon test41 system:system:system:s1:c1 - s1:c1.c3 system:object_r:system:s0 # test 42: # name: unset # ruletype: unset # user: unset # role: unset # type: unset # range: subset netifcon test42 system:system:system:s2:c1 - s2:c1.c3 system:object_r:system:s0 # test 43: # name: unset # user: unset # role: unset # type: unset # range: superset netifcon test43 system:system:system:s3:c1 - s3:c1.c3 system:object_r:system:s0 # test 44: # name: unset # user: unset # role: unset # type: unset # range: proper subset netifcon test44 system:system:system:s4:c1 - s4:c1.c3 system:object_r:system:s0 # test 45: # name: unset # user: unset # role: unset # type: unset # range: proper superset netifcon test45 system:system:system:s5:c1 - s5:c1.c3 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/netifconquery.py000066400000000000000000000214241402045477700176330ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import NetifconQuery from .policyrep.util import compile_policy class NetifconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/netifconquery.conf") def test_000_unset(self): """Netifcon query with no criteria""" # query with no parameters gets all netifs. netifs = sorted(self.p.netifcons()) q = NetifconQuery(self.p) q_netifs = sorted(q.results()) self.assertListEqual(netifs, q_netifs) def test_001_name_exact(self): """Netifcon query with exact match""" q = NetifconQuery(self.p, name="test1", name_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test1"], netifs) def test_002_name_regex(self): """Netifcon query with regex match""" q = NetifconQuery(self.p, name="test2(a|b)", name_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test2a", "test2b"], netifs) def test_010_user_exact(self): """Netifcon query with context user exact match""" q = NetifconQuery(self.p, user="user10", user_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test10"], netifs) def test_011_user_regex(self): """Netifcon query with context user regex match""" q = NetifconQuery(self.p, user="user11(a|b)", user_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test11a", "test11b"], netifs) def test_020_role_exact(self): """Netifcon query with context role exact match""" q = NetifconQuery(self.p, role="role20_r", role_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test20"], netifs) def test_021_role_regex(self): """Netifcon query with context role regex match""" q = NetifconQuery(self.p, role="role21(a|c)_r", role_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test21a", "test21c"], netifs) def test_030_type_exact(self): """Netifcon query with context type exact match""" q = NetifconQuery(self.p, type_="type30", type_regex=False) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test30"], netifs) def test_031_type_regex(self): """Netifcon query with context type regex match""" q = NetifconQuery(self.p, type_="type31(b|c)", type_regex=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test31b", "test31c"], netifs) def test_040_range_exact(self): """Netifcon query with context range exact match""" q = NetifconQuery(self.p, range_="s0:c1 - s0:c0.c4") netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test40"], netifs) def test_041_range_overlap1(self): """Netifcon query with context range overlap match (equal)""" q = NetifconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap2(self): """Netifcon query with context range overlap match (subset)""" q = NetifconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap3(self): """Netifcon query with context range overlap match (superset)""" q = NetifconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap4(self): """Netifcon query with context range overlap match (overlap low level)""" q = NetifconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_041_range_overlap5(self): """Netifcon query with context range overlap match (overlap high level)""" q = NetifconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test41"], netifs) def test_042_range_subset1(self): """Netifcon query with context range subset match""" q = NetifconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test42"], netifs) def test_042_range_subset2(self): """Netifcon query with context range subset match (equal)""" q = NetifconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test42"], netifs) def test_043_range_superset1(self): """Netifcon query with context range superset match""" q = NetifconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test43"], netifs) def test_043_range_superset2(self): """Netifcon query with context range superset match (equal)""" q = NetifconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test43"], netifs) def test_044_range_proper_subset1(self): """Netifcon query with context range proper subset match""" q = NetifconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_044_range_proper_subset2(self): """Netifcon query with context range proper subset match (equal)""" q = NetifconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual([], netifs) def test_044_range_proper_subset3(self): """Netifcon query with context range proper subset match (equal low only)""" q = NetifconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_044_range_proper_subset4(self): """Netifcon query with context range proper subset match (equal high only)""" q = NetifconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test44"], netifs) def test_045_range_proper_superset1(self): """Netifcon query with context range proper superset match""" q = NetifconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) def test_045_range_proper_superset2(self): """Netifcon query with context range proper superset match (equal)""" q = NetifconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual([], netifs) def test_045_range_proper_superset3(self): """Netifcon query with context range proper superset match (equal low)""" q = NetifconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) def test_045_range_proper_superset4(self): """Netifcon query with context range proper superset match (equal high)""" q = NetifconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) netifs = sorted(s.netif for s in q.results()) self.assertListEqual(["test45"], netifs) setools-4.4.0/tests/nodeconquery.conf000066400000000000000000000124761402045477700177570ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role30_r; role role31a_r; role role31b_r; role role31c_r; role role30_r types system; role role31a_r types system; role role31b_r types system; role role31c_r types system; type type40; type type41a; type type41b; type type41c; role system types { type40 type41a type41b type41c }; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles { system role30_r role31a_r role31b_r role31c_r } level s0 range s0 - s6:c0.c4; user user20 roles system level s0 range s0 - s2:c0.c4; user user21a roles system level s0 range s0 - s2:c0.c4; user user21b roles system level s0 range s0 - s2:c0.c4; user user21c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 80 system:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 # test 20: # network: unset # user: user20, exact # role: unset # type: unset # range: unset nodecon 10.1.20.1 255.255.255.255 user20:system:system:s0:c0.c1 # test 21: # network: unset # user: user21(a|b), regex # role: unset # type: unset # range: unset nodecon 10.1.21.1 255.255.255.255 user21a:system:system:s0:c0.c1 nodecon 10.1.21.2 255.255.255.255 user21b:system:system:s0:c0.c1 nodecon 10.1.21.3 255.255.255.255 user21c:system:system:s0:c0.c1 # test 30: # network: unset # user: unset # role: role30_r, exact # type: unset # range: unset nodecon 10.1.30.1 255.255.255.255 system:role30_r:system:s0:c0.c1 # test 31: # network: unset # user: unset # role: role30(a|c)_r, regex # type: unset # range: unset nodecon 10.1.31.1 255.255.255.255 system:role31a_r:system:s0:c0.c1 nodecon 10.1.31.2 255.255.255.255 system:role31b_r:system:s0:c0.c1 nodecon 10.1.31.3 255.255.255.255 system:role31c_r:system:s0:c0.c1 # test 40: # network: unset # user: unset # role: unset # type: type40 # range: unset nodecon 10.1.40.1 255.255.255.255 system:system:type40:s0:c0.c1 # test 41: # network: unset # user: unset # role: unset # type: type41(b|c) # range: unset nodecon 10.1.41.1 255.255.255.255 system:system:type41a:s0:c0.c1 nodecon 10.1.41.2 255.255.255.255 system:system:type41b:s0:c0.c1 nodecon 10.1.41.3 255.255.255.255 system:system:type41c:s0:c0.c1 # test 50: # network: unset # user: unset # role: unset # type: unset # range: equal nodecon 10.1.50.1 255.255.255.255 system:system:system:s0:c1 - s0:c0.c4 # test 51: # network: unset # user: unset # role: unset # type: unset # range: overlap nodecon 10.1.51.1 255.255.255.255 system:system:system:s1:c1 - s1:c1.c3 # test 52: # network: unset # user: unset # role: unset # type: unset # range: subset nodecon 10.1.52.1 255.255.255.255 system:system:system:s2:c1 - s2:c1.c3 # test 53: # network: unset # user: unset # role: unset # type: unset # range: superset nodecon 10.1.53.1 255.255.255.255 system:system:system:s3:c1 - s3:c1.c3 # test 54: # network: unset # user: unset # role: unset # type: unset # range: proper subset nodecon 10.1.54.1 255.255.255.255 system:system:system:s4:c1 - s4:c1.c3 # test 55: # network: unset # user: unset # role: unset # type: unset # range: proper superset nodecon 10.1.55.1 255.255.255.255 system:system:system:s5:c1 - s5:c1.c3 # test 100: # network: 192.168.1.0/24, equal # user: unset # role: unset # type: unset # range: unset nodecon 192.168.1.0 255.255.255.0 system:system:system:s0:c0.c1 # test 101: # network: 192.168.201.0/24, overlap # user: unset # role: unset # type: unset # range: unset nodecon 192.168.200.0 255.255.252.0 system:system:system:s0:c0.c1 # test 110: # network: 1100::/16, equal # user: unset # role: unset # type: unset # range: unset nodecon 1100:: ffff:: system:system:system:s0:c0.c1 # test 111: # network: 1110:8000::/17, overlap # user: unset # role: unset # type: unset # range: unset nodecon 1110:: ffff:: system:system:system:s0:c0.c1 setools-4.4.0/tests/nodeconquery.py000066400000000000000000000247421402045477700174610ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # Copyright 2017, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from socket import AF_INET6 from ipaddress import IPv4Network, IPv6Network from setools import NodeconQuery from .policyrep.util import compile_policy class NodeconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/nodeconquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Nodecon query with no criteria""" # query with no parameters gets all nodecons. nodecons = sorted(self.p.nodecons()) q = NodeconQuery(self.p) q_nodecons = sorted(q.results()) self.assertListEqual(nodecons, q_nodecons) def test_001_ip_version(self): """Nodecon query with IP version match.""" q = NodeconQuery(self.p, ip_version=AF_INET6) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv6Network("1100::/16"), IPv6Network("1110::/16")], nodecons) def test_020_user_exact(self): """Nodecon query with context user exact match""" q = NodeconQuery(self.p, user="user20", user_regex=False) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.20.1/32")], nodecons) def test_021_user_regex(self): """Nodecon query with context user regex match""" q = NodeconQuery(self.p, user="user21(a|b)", user_regex=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.21.1/32"), IPv4Network("10.1.21.2/32")], nodecons) def test_030_role_exact(self): """Nodecon query with context role exact match""" q = NodeconQuery(self.p, role="role30_r", role_regex=False) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.30.1/32")], nodecons) def test_031_role_regex(self): """Nodecon query with context role regex match""" q = NodeconQuery(self.p, role="role31(a|c)_r", role_regex=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.31.1/32"), IPv4Network("10.1.31.3/32")], nodecons) def test_040_type_exact(self): """Nodecon query with context type exact match""" q = NodeconQuery(self.p, type_="type40", type_regex=False) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.40.1/32")], nodecons) def test_041_type_regex(self): """Nodecon query with context type regex match""" q = NodeconQuery(self.p, type_="type41(b|c)", type_regex=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.41.2/32"), IPv4Network("10.1.41.3/32")], nodecons) def test_050_range_exact(self): """Nodecon query with context range exact match""" q = NodeconQuery(self.p, range_="s0:c1 - s0:c0.c4") nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.50.1/32")], nodecons) def test_051_range_overlap1(self): """Nodecon query with context range overlap match (equal)""" q = NodeconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.51.1/32")], nodecons) def test_051_range_overlap2(self): """Nodecon query with context range overlap match (subset)""" q = NodeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.51.1/32")], nodecons) def test_051_range_overlap3(self): """Nodecon query with context range overlap match (superset)""" q = NodeconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.51.1/32")], nodecons) def test_051_range_overlap4(self): """Nodecon query with context range overlap match (overlap low level)""" q = NodeconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.51.1/32")], nodecons) def test_051_range_overlap5(self): """Nodecon query with context range overlap match (overlap high level)""" q = NodeconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.51.1/32")], nodecons) def test_052_range_subset1(self): """Nodecon query with context range subset match""" q = NodeconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.52.1/32")], nodecons) def test_052_range_subset2(self): """Nodecon query with context range subset match (equal)""" q = NodeconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.52.1/32")], nodecons) def test_053_range_superset1(self): """Nodecon query with context range superset match""" q = NodeconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.53.1/32")], nodecons) def test_053_range_superset2(self): """Nodecon query with context range superset match (equal)""" q = NodeconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.53.1/32")], nodecons) def test_054_range_proper_subset1(self): """Nodecon query with context range proper subset match""" q = NodeconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.54.1/32")], nodecons) def test_054_range_proper_subset2(self): """Nodecon query with context range proper subset match (equal)""" q = NodeconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([], nodecons) def test_054_range_proper_subset3(self): """Nodecon query with context range proper subset match (equal low only)""" q = NodeconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.54.1/32")], nodecons) def test_054_range_proper_subset4(self): """Nodecon query with context range proper subset match (equal high only)""" q = NodeconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.54.1/32")], nodecons) def test_055_range_proper_superset1(self): """Nodecon query with context range proper superset match""" q = NodeconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.55.1/32")], nodecons) def test_055_range_proper_superset2(self): """Nodecon query with context range proper superset match (equal)""" q = NodeconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([], nodecons) def test_055_range_proper_superset3(self): """Nodecon query with context range proper superset match (equal low)""" q = NodeconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.55.1/32")], nodecons) def test_055_range_proper_superset4(self): """Nodecon query with context range proper superset match (equal high)""" q = NodeconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("10.1.55.1/32")], nodecons) def test_100_v4network_equal(self): """Nodecon query with IPv4 equal network""" q = NodeconQuery(self.p, network="192.168.1.0/24", network_overlap=False) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("192.168.1.0/24")], nodecons) def test_101_v4network_overlap(self): """Nodecon query with IPv4 network overlap""" q = NodeconQuery(self.p, network="192.168.201.0/24", network_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv4Network("192.168.200.0/22")], nodecons) def test_110_v6network_equal(self): """Nodecon query with IPv6 equal network""" q = NodeconQuery(self.p, network="1100::/16", network_overlap=False) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv6Network("1100::/16")], nodecons) def test_111_v6network_overlap(self): """Nodecon query with IPv6 network overlap""" q = NodeconQuery(self.p, network="1110:8000::/17", network_overlap=True) nodecons = sorted(n.network for n in q.results()) self.assertListEqual([IPv6Network("1110::/16")], nodecons) setools-4.4.0/tests/objclassquery.conf000066400000000000000000000041131402045477700201170ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class infoflow8 class infoflow9 class infoflow10 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } common com_a { hi_w hi_r super_r super_w } common com_b { send recv } common com_c { getattr setattr read write } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow { super_w super_r super_none super_both super_unmapped } class infoflow5 inherits com_a class infoflow6 inherits com_b class infoflow7 inherits infoflow { unmapped } class infoflow8 { super_w super_r } class infoflow9 inherits com_c class infoflow10 { read write } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; allow system system:infoflow3 null; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/objclassquery.py000066400000000000000000000111141402045477700176210ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import ObjClassQuery from .policyrep.util import compile_policy class ObjClassQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/objclassquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Class query with no criteria.""" # query with no parameters gets all types. classes = sorted(self.p.classes()) q = ObjClassQuery(self.p) q_classes = sorted(q.results()) self.assertListEqual(classes, q_classes) def test_001_name_exact(self): """Class query with exact name match.""" q = ObjClassQuery(self.p, name="infoflow") classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow"], classes) def test_002_name_regex(self): """Class query with regex name match.""" q = ObjClassQuery(self.p, name="infoflow(2|3)", name_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow3"], classes) def test_010_common_exact(self): """Class query with exact common name match.""" q = ObjClassQuery(self.p, common="infoflow") classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow", "infoflow2", "infoflow4", "infoflow7"], classes) def test_011_common_regex(self): """Class query with regex common name match.""" q = ObjClassQuery(self.p, common="com_[ab]", common_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow5", "infoflow6"], classes) def test_020_perm_indirect_intersect(self): """Class query with indirect, intersect permission name patch.""" q = ObjClassQuery( self.p, perms=set(["send"]), perms_indirect=True, perms_equal=False) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow6"], classes) def test_021_perm_direct_intersect(self): """Class query with direct, intersect permission name patch.""" q = ObjClassQuery( self.p, perms=set(["super_r"]), perms_indirect=False, perms_equal=False) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow4", "infoflow8"], classes) def test_022_perm_indirect_equal(self): """Class query with indirect, equal permission name patch.""" q = ObjClassQuery(self.p, perms=set( ["low_w", "med_w", "hi_w", "low_r", "med_r", "hi_r", "unmapped"]), perms_indirect=True, perms_equal=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow7"], classes) def test_023_perm_direct_equal(self): """Class query with direct, equal permission name patch.""" q = ObjClassQuery(self.p, perms=set( ["super_r", "super_w"]), perms_indirect=False, perms_equal=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow2", "infoflow8"], classes) def test_024_perm_indirect_regex(self): """Class query with indirect, regex permission name patch.""" q = ObjClassQuery( self.p, perms="(send|setattr)", perms_indirect=True, perms_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow6", "infoflow9"], classes) def test_025_perm_direct_regex(self): """Class query with direct, regex permission name patch.""" q = ObjClassQuery( self.p, perms="(read|super_r)", perms_indirect=False, perms_regex=True) classes = sorted(str(c) for c in q.results()) self.assertListEqual(["infoflow10", "infoflow2", "infoflow4", "infoflow8"], classes) setools-4.4.0/tests/pcideviceconquery.conf000066400000000000000000000076341402045477700207650ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # pci device: unset # user: unset # role: unset # type: unset # range: unset pcidevicecon 1 system:system:system:s0:c0.c1 # test 10: # pci device: unset # user: user10, exact # role: unset # type: unset # range: unset pcidevicecon 10 user10:system:system:s0:c0.c1 # test 11: # pci device: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset pcidevicecon 11 user11a:system:system:s0:c0.c1 pcidevicecon 11000 user11b:system:system:s0:c0.c1 pcidevicecon 11001 user11c:system:system:s0:c0.c1 # test 20: # pci device: unset # user: unset # role: role20_r, exact # type: unset # range: unset pcidevicecon 20 system:role20_r:system:s0:c0.c1 # test 21: # pci device: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset pcidevicecon 21 system:role21a_r:system:s0:c0.c1 pcidevicecon 21000 system:role21b_r:system:s0:c0.c1 pcidevicecon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # pci device: unset # user: unset # role: unset # type: type30 # range: unset pcidevicecon 30 system:system:type30:s0:c0.c1 # test 31: # pci device: unset # user: unset # role: unset # type: type31(b|c) # range: unset pcidevicecon 31 system:system:type31a:s0:c0.c1 pcidevicecon 31000 system:system:type31b:s0:c0.c1 pcidevicecon 31001 system:system:type31c:s0:c0.c1 # test 40: # pci device: unset # user: unset # role: unset # type: unset # range: equal pcidevicecon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # pci device: unset # user: unset # role: unset # type: unset # range: overlap pcidevicecon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # pci device: unset # user: unset # role: unset # type: unset # range: subset pcidevicecon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # pci device: unset # user: unset # role: unset # type: unset # range: superset pcidevicecon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # pci device: unset # user: unset # role: unset # type: unset # range: proper subset pcidevicecon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # pci device: unset # user: unset # role: unset # type: unset # range: proper superset pcidevicecon 45 system:system:system:s5:c1 - s5:c1.c3 setools-4.4.0/tests/pcideviceconquery.py000066400000000000000000000212541402045477700204620ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import PcideviceconQuery from .policyrep.util import compile_policy class PcideviceconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/pcideviceconquery.conf", xen=True) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Pcidevicecon query with no criteria""" # query with no parameters gets all PCI devices. rules = sorted(self.p.pcidevicecons()) q = PcideviceconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Pcidevicecon query with context user exact match""" q = PcideviceconQuery(self.p, user="user10", user_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(10)], device) def test_011_user_regex(self): """Pcidevicecon query with context user regex match""" q = PcideviceconQuery(self.p, user="user11(a|b)", user_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(11), (11000)], device) def test_020_role_exact(self): """Pcidevicecon query with context role exact match""" q = PcideviceconQuery(self.p, role="role20_r", role_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(20)], device) def test_021_role_regex(self): """Pcidevicecon query with context role regex match""" q = PcideviceconQuery(self.p, role="role21(a|c)_r", role_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(21), (21001)], device) def test_030_type_exact(self): """Pcidevicecon query with context type exact match""" q = PcideviceconQuery(self.p, type_="type30", type_regex=False) device = sorted(p.device for p in q.results()) self.assertListEqual([(30)], device) def test_031_type_regex(self): """Pcidevicecon query with context type regex match""" q = PcideviceconQuery(self.p, type_="type31(b|c)", type_regex=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(31000), (31001)], device) def test_040_range_exact(self): """Pcidevicecon query with context range exact match""" q = PcideviceconQuery(self.p, range_="s0:c1 - s0:c0.c4") device = sorted(p.device for p in q.results()) self.assertListEqual([(40)], device) def test_041_range_overlap1(self): """Pcidevicecon query with context range overlap match (equal)""" q = PcideviceconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap2(self): """Pcidevicecon query with context range overlap match (subset)""" q = PcideviceconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap3(self): """Pcidevicecon query with context range overlap match (superset)""" q = PcideviceconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap4(self): """Pcidevicecon query with context range overlap match (overlap low level)""" q = PcideviceconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_041_range_overlap5(self): """Pcidevicecon query with context range overlap match (overlap high level)""" q = PcideviceconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(41)], device) def test_042_range_subset1(self): """Pcidevicecon query with context range subset match""" q = PcideviceconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(42)], device) def test_042_range_subset2(self): """Pcidevicecon query with context range subset match (equal)""" q = PcideviceconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(42)], device) def test_043_range_superset1(self): """Pcidevicecon query with context range superset match""" q = PcideviceconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(43)], device) def test_043_range_superset2(self): """Pcidevicecon query with context range superset match (equal)""" q = PcideviceconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(43)], device) def test_044_range_proper_subset1(self): """Pcidevicecon query with context range proper subset match""" q = PcideviceconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_044_range_proper_subset2(self): """Pcidevicecon query with context range proper subset match (equal)""" q = PcideviceconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([], device) def test_044_range_proper_subset3(self): """Pcidevicecon query with context range proper subset match (equal low only)""" q = PcideviceconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_044_range_proper_subset4(self): """Pcidevicecon query with context range proper subset match (equal high only)""" q = PcideviceconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(44)], device) def test_045_range_proper_superset1(self): """Pcidevicecon query with context range proper superset match""" q = PcideviceconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) def test_045_range_proper_superset2(self): """Pcidevicecon query with context range proper superset match (equal)""" q = PcideviceconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([], device) def test_045_range_proper_superset3(self): """Pcidevicecon query with context range proper superset match (equal low)""" q = PcideviceconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) def test_045_range_proper_superset4(self): """Pcidevicecon query with context range proper superset match (equal high)""" q = PcideviceconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) device = sorted(p.device for p in q.results()) self.assertListEqual([(45)], device) setools-4.4.0/tests/perm_map000066400000000000000000000010051402045477700161020ustar00rootroot00000000000000# this is an early comment 5 # this is a comment before a class class infoflow 6 low_w w 1 med_w w 5 hi_w w 10 low_r r 1 med_r r 5 hi_r r 10 # this a comment between classes class infoflow2 7 # this is a comment before perms low_w w 1 med_w w 5 hi_w w 10 # this is a comment between perms low_r r 1 # this is a comment after a perm med_r r 5 hi_r r 10 super b 10 class infoflow3 1 null n 1 class file 2 execute r 10 entrypoint r 10 class process 1 transition w 10 # this is an extra comment at the end setools-4.4.0/tests/permmap.conf000066400000000000000000000067411402045477700167030ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class file class process class new_class sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super new_perm } class infoflow3 { null } class new_class { new_class_perm } class file { execute entrypoint } class process { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Note: these tests should be to determine if the graph # is being constructed correctly. It is assumed that the # graph algorithms being used are correct, as they are # unit tested by the NetworkX project itself. # # # Max steps for all flows: 6 # # Graph if min weight is 8 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ # 1 -> 2-/ # # 3 5 -> 8 <-> 9 # # Graph if min weight is 3 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 5 -> 8 <-> 9 # # Graph if min weight is 1 # # # 4 -> 6 -> 7 d1 <-> d2 # ^ | # 1 -> 2-/ | # \ v # -> 3 -> 5 -> 8 <-> 9 # # # attribute allnodes; type node1, allnodes; type node2, allnodes; type node3, allnodes; type node4, allnodes; type node5, allnodes; type node6, allnodes; type node7, allnodes; type node8, allnodes; type node9, allnodes; # no infoflow allow allnodes allnodes:infoflow3 null; # 1->2 (10, 5) allow node1 node2:infoflow med_w; allow node2 node1:infoflow hi_r; # 1->3 (5, 1) allow node3 node1:infoflow { low_r med_r }; # 2->4 (10) allow node2 node4:infoflow hi_w; # 3->5 (1) allow node5 node3:infoflow low_r; # 4->6 (10) allow node4 node6:infoflow2 hi_w; # 6->5 (5) allow node5 node6:infoflow med_r; # 6->7 (10) allow node6 node7:infoflow hi_w; # 5->8 (10) allow node5 node8:infoflow2 hi_w; # 8 <-> 9 (10) allow node8 node9:infoflow2 super; # disconnected from the main graph # for testing the handling of no # paths. type disconnected1; type disconnected2; allow disconnected1 disconnected2:infoflow2 super; # not an infoflow: type disconnected3; auditallow node1 disconnected3:infoflow hi_w; # infoflow loop that should be ignored: allow disconnected3 self:infoflow hi_w; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/permmap.py000066400000000000000000000407661402045477700164130ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import unittest import os from unittest.mock import Mock from setools import PermissionMap, TERuletype from setools.exception import PermissionMapParseError, RuleTypeError, \ UnmappedClass, UnmappedPermission from .policyrep.util import compile_policy class PermissionMapTest(unittest.TestCase): """Permission map unit tests.""" @classmethod def setUpClass(cls): cls.p = compile_policy("tests/permmap.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def validate_permmap_entry(self, permmap, cls, perm, direction, weight, enabled): """Validate a permission map entry and settings.""" self.assertIn(cls, permmap) self.assertIn(perm, permmap[cls]) self.assertIn('direction', permmap[cls][perm]) self.assertIn('weight', permmap[cls][perm]) self.assertIn('enabled', permmap[cls][perm]) self.assertEqual(permmap[cls][perm]['direction'], direction) self.assertEqual(permmap[cls][perm]['weight'], weight) if enabled: self.assertTrue(permmap[cls][perm]['enabled']) else: self.assertFalse(permmap[cls][perm]['enabled']) def test_001_load(self): """PermMap open from path.""" permmap = PermissionMap("tests/perm_map") # validate permission map contents self.assertEqual(5, len(permmap._permmap)) # class infoflow self.assertIn("infoflow", permmap._permmap) self.assertEqual(6, len(permmap._permmap['infoflow'])) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'low_w', 'w', 1, True) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'med_w', 'w', 5, True) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'hi_w', 'w', 10, True) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'low_r', 'r', 1, True) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'med_r', 'r', 5, True) self.validate_permmap_entry(permmap._permmap, 'infoflow', 'hi_r', 'r', 10, True) # class infoflow2 self.assertIn("infoflow2", permmap._permmap) self.assertEqual(7, len(permmap._permmap['infoflow2'])) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_w', 'w', 1, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'med_w', 'w', 5, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'hi_w', 'w', 10, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_r', 'r', 1, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'med_r', 'r', 5, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'hi_r', 'r', 10, True) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'super', 'b', 10, True) # class infoflow3 self.assertIn("infoflow3", permmap._permmap) self.assertEqual(1, len(permmap._permmap['infoflow3'])) self.validate_permmap_entry(permmap._permmap, 'infoflow3', 'null', 'n', 1, True) # class file self.assertIn("file", permmap._permmap) self.assertEqual(2, len(permmap._permmap['file'])) self.validate_permmap_entry(permmap._permmap, 'file', 'execute', 'r', 10, True) self.validate_permmap_entry(permmap._permmap, 'file', 'entrypoint', 'r', 10, True) # class process self.assertIn("process", permmap._permmap) self.assertEqual(1, len(permmap._permmap['process'])) self.validate_permmap_entry(permmap._permmap, 'process', 'transition', 'w', 10, True) def test_002_load_invalid(self): """PermMap load completely wrong file type""" with self.assertRaises(PermissionMapParseError): PermissionMap("setup.py") def test_002_load_negative_class_count(self): """PermMap load negative class count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/negative-classcount") def test_003_load_non_number_class_count(self): """PermMap load non-number class count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/non-number-classcount") def test_004_load_extra_class(self): """PermMap load extra class""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/extra-class") def test_005_load_bad_class_keyword(self): """PermMap load bad class keyword""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-class-keyword") # test 6: bad class name(?) def test_007_load_negative_perm_count(self): """PermMap load negative permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/negative-permcount") def test_008_load_bad_perm_count(self): """PermMap load bad permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-permcount") # test 9: bad perm name(?) def test_010_load_extra_perms(self): """PermMap load negative permission count""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/extra-perms") def test_011_load_invalid_flow_direction(self): """PermMap load invalid flow direction""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/invalid-flowdir") def test_012_load_bad_perm_weight(self): """PermMap load too high/low permission weight""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-perm-weight-high") with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/bad-perm-weight-low") def test_013_load_invalid_weight(self): """PermMap load invalid permission weight""" with self.assertRaises(PermissionMapParseError): PermissionMap("tests/invalid_perm_maps/invalid-perm-weight") def test_100_set_weight(self): """PermMap set weight""" permmap = PermissionMap("tests/perm_map") self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_w', 'w', 1, True) permmap.set_weight("infoflow2", "low_w", 10) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_w', 'w', 10, True) def test_101_set_weight_low(self): """PermMap set weight low""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 0) with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", -10) def test_102_set_weight_low(self): """PermMap set weight high""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 11) with self.assertRaises(ValueError): permmap.set_weight("infoflow2", "low_w", 50) def test_103_set_weight_unmapped_class(self): """PermMap set weight unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.set_weight("UNMAPPED", "write", 10) def test_104_set_weight_unmapped_permission(self): """PermMap set weight unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.set_weight("infoflow2", "UNMAPPED", 10) def test_110_set_direction(self): """PermMap set direction""" permmap = PermissionMap("tests/perm_map") self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_w', 'w', 1, True) permmap.set_direction("infoflow2", "low_w", "r") self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'low_w', 'r', 1, True) def test_111_set_direction_invalid(self): """PermMap set invalid direction""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(ValueError): permmap.set_direction("infoflow2", "low_w", "X") def test_112_set_direction_unmapped_class(self): """PermMap set direction unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.set_direction("UNMAPPED", "write", "w") def test_113_set_direction_unmapped_permission(self): """PermMap set direction unmapped class""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.set_direction("infoflow2", "UNMAPPED", "w") def test_120_exclude_perm(self): """PermMap exclude permission.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "med_w") self.validate_permmap_entry(permmap._permmap, 'infoflow', 'med_w', 'w', 5, False) def test_121_exclude_perm_unmapped_class(self): """PermMap exclude permission unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.exclude_permission("UNMAPPED", "med_w") def test_122_exclude_perm_unmapped_perm(self): """PermMap exclude permission unmapped permission.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.exclude_permission("infoflow", "UNMAPPED") def test_123_include_perm(self): """PermMap include permission.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "med_w") self.validate_permmap_entry(permmap._permmap, 'infoflow', 'med_w', 'w', 5, False) permmap.include_permission("infoflow", "med_w") self.validate_permmap_entry(permmap._permmap, 'infoflow', 'med_w', 'w', 5, True) def test_124_include_perm_unmapped_class(self): """PermMap include permission unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.include_permission("UNMAPPED", "med_w") def test_125_include_perm_unmapped_perm(self): """PermMap include permission unmapped permission.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedPermission): permmap.include_permission("infoflow", "UNMAPPED") def test_130_exclude_class(self): """PermMap exclude class.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_class("file") self.validate_permmap_entry(permmap._permmap, 'file', 'execute', 'r', 10, False) self.validate_permmap_entry(permmap._permmap, 'file', 'entrypoint', 'r', 10, False) def test_131_exclude_class_unmapped_class(self): """PermMap exclude class unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.exclude_class("UNMAPPED") def test_132_include_class(self): """PermMap exclude class.""" permmap = PermissionMap("tests/perm_map") permmap.exclude_class("file") self.validate_permmap_entry(permmap._permmap, 'file', 'execute', 'r', 10, False) self.validate_permmap_entry(permmap._permmap, 'file', 'entrypoint', 'r', 10, False) permmap.include_class("file") self.validate_permmap_entry(permmap._permmap, 'file', 'execute', 'r', 10, True) self.validate_permmap_entry(permmap._permmap, 'file', 'entrypoint', 'r', 10, True) def test_133_include_class_unmapped_class(self): """PermMap include class unmapped class.""" permmap = PermissionMap("tests/perm_map") with self.assertRaises(UnmappedClass): permmap.include_class("UNMAPPED") def test_140_weight_read_only(self): """PermMap get weight of read-only rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["med_r", "hi_r"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 10) self.assertEqual(w, 0) def test_141_weight_write_only(self): """PermMap get weight of write-only rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_w", "med_w"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 5) def test_142_weight_both(self): """PermMap get weight of both rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "hi_w"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 1) self.assertEqual(w, 10) def test_143_weight_none(self): """PermMap get weight of none rule.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow3" rule.perms = set(["null"]) permmap = PermissionMap("tests/perm_map") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 0) def test_144_weight_unmapped_class(self): """PermMap get weight of rule with unmapped class.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "unmapped" rule.perms = set(["null"]) permmap = PermissionMap("tests/perm_map") self.assertRaises(UnmappedClass, permmap.rule_weight, rule) def test_145_weight_unmapped_permission(self): """PermMap get weight of rule with unmapped permission.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "unmapped"]) permmap = PermissionMap("tests/perm_map") self.assertRaises(UnmappedPermission, permmap.rule_weight, rule) def test_146_weight_wrong_rule_type(self): """PermMap get weight of rule with wrong rule type.""" rule = Mock() rule.ruletype = TERuletype.type_transition rule.tclass = "infoflow" permmap = PermissionMap("tests/perm_map") self.assertRaises(RuleTypeError, permmap.rule_weight, rule) def test_147_weight_excluded_permission(self): """PermMap get weight of a rule with excluded permission.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["med_r", "hi_r"]) permmap = PermissionMap("tests/perm_map") permmap.exclude_permission("infoflow", "hi_r") r, w = permmap.rule_weight(rule) self.assertEqual(r, 5) self.assertEqual(w, 0) def test_148_weight_excluded_class(self): """PermMap get weight of a rule with excluded class.""" rule = Mock() rule.ruletype = TERuletype.allow rule.tclass = "infoflow" rule.perms = set(["low_r", "med_r", "hi_r", "low_w", "med_w", "hi_w"]) permmap = PermissionMap("tests/perm_map") permmap.exclude_class("infoflow") r, w = permmap.rule_weight(rule) self.assertEqual(r, 0) self.assertEqual(w, 0) def test_150_map_policy(self): """PermMap create mappings for classes/perms in a policy.""" permmap = PermissionMap("tests/perm_map") permmap.map_policy(self.p) self.validate_permmap_entry(permmap._permmap, 'infoflow2', 'new_perm', 'u', 1, True) self.assertIn("new_class", permmap._permmap) self.assertEqual(1, len(permmap._permmap['new_class'])) self.validate_permmap_entry(permmap._permmap, 'new_class', 'new_class_perm', 'u', 1, True) setools-4.4.0/tests/pirqconquery.conf000066400000000000000000000073421402045477700200010ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 # test 1: # irq: unset # user: unset # role: unset # type: unset # range: unset pirqcon 1 system:system:system:s0:c0.c1 # test 10: # irq: unset # user: user10, exact # role: unset # type: unset # range: unset pirqcon 10 user10:system:system:s0:c0.c1 # test 11: # irq: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset pirqcon 11 user11a:system:system:s0:c0.c1 pirqcon 11000 user11b:system:system:s0:c0.c1 pirqcon 11001 user11c:system:system:s0:c0.c1 # test 20: # irq: unset # user: unset # role: role20_r, exact # type: unset # range: unset pirqcon 20 system:role20_r:system:s0:c0.c1 # test 21: # irq: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset pirqcon 21 system:role21a_r:system:s0:c0.c1 pirqcon 21000 system:role21b_r:system:s0:c0.c1 pirqcon 21001 system:role21c_r:system:s0:c0.c1 # test 30: # irq: unset # user: unset # role: unset # type: type30 # range: unset pirqcon 30 system:system:type30:s0:c0.c1 # test 31: # irq: unset # user: unset # role: unset # type: type31(b|c) # range: unset pirqcon 31 system:system:type31a:s0:c0.c1 pirqcon 31000 system:system:type31b:s0:c0.c1 pirqcon 31001 system:system:type31c:s0:c0.c1 # test 40: # irq: unset # user: unset # role: unset # type: unset # range: equal pirqcon 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # irq: unset # user: unset # role: unset # type: unset # range: overlap pirqcon 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # irq: unset # user: unset # role: unset # type: unset # range: subset pirqcon 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # irq: unset # user: unset # role: unset # type: unset # range: superset pirqcon 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # irq: unset # user: unset # role: unset # type: unset # range: proper subset pirqcon 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # irq: unset # user: unset # role: unset # type: unset # range: proper superset pirqcon 45 system:system:system:s5:c1 - s5:c1.c3 setools-4.4.0/tests/pirqconquery.py000066400000000000000000000177611402045477700175120ustar00rootroot00000000000000# Derived from tests/portconquery.py # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import PirqconQuery from .policyrep.util import compile_policy class PirqconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/pirqconquery.conf", xen=True) @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Pirqcon query with no criteria""" # query with no parameters gets all PCI irqs. rules = sorted(self.p.pirqcons()) q = PirqconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_010_user_exact(self): """Pirqcon query with context user exact match""" q = PirqconQuery(self.p, user="user10", user_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(10)], irq) def test_011_user_regex(self): """Pirqcon query with context user regex match""" q = PirqconQuery(self.p, user="user11(a|b)", user_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(11), (11000)], irq) def test_020_role_exact(self): """Pirqcon query with context role exact match""" q = PirqconQuery(self.p, role="role20_r", role_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(20)], irq) def test_021_role_regex(self): """Pirqcon query with context role regex match""" q = PirqconQuery(self.p, role="role21(a|c)_r", role_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(21), (21001)], irq) def test_030_type_exact(self): """Pirqcon query with context type exact match""" q = PirqconQuery(self.p, type_="type30", type_regex=False) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(30)], irq) def test_031_type_regex(self): """Pirqcon query with context type regex match""" q = PirqconQuery(self.p, type_="type31(b|c)", type_regex=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(31000), (31001)], irq) def test_040_range_exact(self): """Pirqcon query with context range exact match""" q = PirqconQuery(self.p, range_="s0:c1 - s0:c0.c4") irq = sorted(p.irq for p in q.results()) self.assertListEqual([(40)], irq) def test_041_range_overlap1(self): """Pirqcon query with context range overlap match (equal)""" q = PirqconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap2(self): """Pirqcon query with context range overlap match (subset)""" q = PirqconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap3(self): """Pirqcon query with context range overlap match (superset)""" q = PirqconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap4(self): """Pirqcon query with context range overlap match (overlap low level)""" q = PirqconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_041_range_overlap5(self): """Pirqcon query with context range overlap match (overlap high level)""" q = PirqconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(41)], irq) def test_042_range_subset1(self): """Pirqcon query with context range subset match""" q = PirqconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(42)], irq) def test_042_range_subset2(self): """Pirqcon query with context range subset match (equal)""" q = PirqconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(42)], irq) def test_043_range_superset1(self): """Pirqcon query with context range superset match""" q = PirqconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(43)], irq) def test_043_range_superset2(self): """Pirqcon query with context range superset match (equal)""" q = PirqconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(43)], irq) def test_044_range_proper_subset1(self): """Pirqcon query with context range proper subset match""" q = PirqconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_044_range_proper_subset2(self): """Pirqcon query with context range proper subset match (equal)""" q = PirqconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([], irq) def test_044_range_proper_subset3(self): """Pirqcon query with context range proper subset match (equal low only)""" q = PirqconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_044_range_proper_subset4(self): """Pirqcon query with context range proper subset match (equal high only)""" q = PirqconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(44)], irq) def test_045_range_proper_superset1(self): """Pirqcon query with context range proper superset match""" q = PirqconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) def test_045_range_proper_superset2(self): """Pirqcon query with context range proper superset match (equal)""" q = PirqconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([], irq) def test_045_range_proper_superset3(self): """Pirqcon query with context range proper superset match (equal low)""" q = PirqconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) def test_045_range_proper_superset4(self): """Pirqcon query with context range proper superset match (equal high)""" q = PirqconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) irq = sorted(p.irq for p in q.results()) self.assertListEqual([(45)], irq) setools-4.4.0/tests/polcapquery.conf000066400000000000000000000044461402045477700176060ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # Policy capabilities query # # this is not as good of a test suite since # the capabilities can only have specific names. # test 1 # name: open_perms policycap open_perms; # test 2 # name: pe?er regex # default: unset # note this should get both capabilities. policycap network_peer_controls; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/polcapquery.py000066400000000000000000000035141402045477700173040ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import PolCapQuery from .policyrep.util import compile_policy class PolCapQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/polcapquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Policy capability query with no criteria""" # query with no parameters gets all capabilities. allcaps = sorted(self.p.polcaps()) q = PolCapQuery(self.p) qcaps = sorted(q.results()) self.assertListEqual(allcaps, qcaps) def test_001_name_exact(self): """Policy capability query with exact match""" q = PolCapQuery(self.p, name="open_perms", name_regex=False) caps = sorted(str(c) for c in q.results()) self.assertListEqual(["open_perms"], caps) def test_002_name_regex(self): """Policy capability query with regex match""" q = PolCapQuery(self.p, name="pe?er", name_regex=True) caps = sorted(str(c) for c in q.results()) self.assertListEqual(["network_peer_controls", "open_perms"], caps) setools-4.4.0/tests/policyrep/000077500000000000000000000000001402045477700163715ustar00rootroot00000000000000setools-4.4.0/tests/policyrep/__init__.py000066400000000000000000000017311402045477700205040ustar00rootroot00000000000000# Copyright 2015-2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # from . import default from . import initsid from . import mls from . import mlsrule from . import objclass from . import polcap from . import rbacrule from . import role from . import selinuxpolicy from . import symbol from . import terule from . import typeattr from . import user setools-4.4.0/tests/policyrep/default.py000066400000000000000000000176101402045477700203740ustar00rootroot00000000000000# Copyright 2016, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import unittest from unittest.mock import Mock, patch from setools.exception import InvalidDefaultType, InvalidDefaultValue, \ InvalidDefaultRange, NoDefaults @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class DefaultTest(unittest.TestCase): @staticmethod def mock_default(objclass=None, user=None, role=None, type_=None, range_=None): d = Mock(qpol_default_object_t) d.object_class.return_value = objclass d.user_default.return_value = user d.role_default.return_value = role d.type_default.return_value = type_ d.range_default.return_value = range_ return d def setUp(self): self.p = Mock(qpol_policy_t) def test_001_factory_user(self): """Default: factory on qpol object with user default.""" q = self.mock_default("test1", "source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test1", d.tclass) self.assertEqual(DefaultValue.source, d.default) def test_002_factory_role(self): """Default: factory on qpol object with role default.""" q = self.mock_default("test2", role="target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test2", d.tclass) self.assertEqual(DefaultValue.target, d.default) def test_003_factory_type(self): """Default: factory on qpol object with type default.""" q = self.mock_default("test3", type_="source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test3", d.tclass) self.assertEqual(DefaultValue.source, d.default) def test_004_factory_range(self): """Default: factory on qpol object with range default.""" q = self.mock_default("test4", range_="target low_high") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test4", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual(DefaultRangeValue.low_high, d.default_range) def test_005_factory_multiple(self): """Default: factory on qpol object with mulitple defaults.""" q = self.mock_default("test5", "source", "target", "source", "target low") defaults = sorted(default_factory(self.p, q)) self.assertEqual(4, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[1] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[2] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test5", d.tclass) d = defaults[3] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test5", d.tclass) def test_010_user(self): """Default: default_user methods/attributes.""" q = self.mock_default("test10", "target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_user, d.ruletype) self.assertEqual("test10", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual("default_user test10 target;", str(d)) self.assertEqual(str(d), d.statement()) def test_011_role(self): """Default: default_role methods/attributes.""" q = self.mock_default("test11", role="source") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_role, d.ruletype) self.assertEqual("test11", d.tclass) self.assertEqual(DefaultValue.source, d.default) self.assertEqual("default_role test11 source;", str(d)) self.assertEqual(str(d), d.statement()) def test_012_type(self): """Default: default_type methods/attributes.""" q = self.mock_default("test12", type_="target") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_type, d.ruletype) self.assertEqual("test12", d.tclass) self.assertEqual(DefaultValue.target, d.default) self.assertEqual("default_type test12 target;", str(d)) self.assertEqual(str(d), d.statement()) def test_013_range(self): """Default: default_range methods/attributes.""" q = self.mock_default("test13", range_="source high") defaults = list(default_factory(self.p, q)) self.assertEqual(1, len(defaults)) d = defaults[0] self.assertEqual(DefaultRuletype.default_range, d.ruletype) self.assertEqual("test13", d.tclass) self.assertEqual(DefaultValue.source, d.default) self.assertEqual(DefaultRangeValue.high, d.default_range) self.assertEqual("default_range test13 source high;", str(d)) self.assertEqual(str(d), d.statement()) @unittest.skip("Default ruletype changed to an enumeration.") def test_020_validate_ruletype(self): """Default: validate rule type.""" for r in ["default_user", "default_role", "default_type", "default_range"]: self.assertEqual(r, validate_ruletype(r)) @unittest.skip("Default ruletype changed to an enumeration.") def test_021_validate_ruletype_invalid(self): """Default: invalid ruletype""" with self.assertRaises(InvalidDefaultType): validate_ruletype("INVALID") @unittest.skip("Default value changed to an enumeration.") def test_030_validate_default(self): """Default: validate default value.""" for d in ["source", "target"]: self.assertEqual(d, validate_default_value(d)) @unittest.skip("Default value changed to an enumeration.") def test_031_validate_default_invalid(self): """Default query: invalid default value""" with self.assertRaises(InvalidDefaultValue): validate_default_value("INVALID") @unittest.skip("Default range value changed to an enumeration.") def test_040_validate_default_range(self): """Default: validate default range.""" for r in ["low", "high", "low_high"]: self.assertEqual(r, validate_default_range(r)) @unittest.skip("Default range value changed to an enumeration.") def test_041_validate_default_range_invalid(self): """Default query: invalid default range""" with self.assertRaises(InvalidDefaultRange): validate_default_range("INVALID") setools-4.4.0/tests/policyrep/initsid.conf000066400000000000000000000044401402045477700207050ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } 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; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/initsid.py000066400000000000000000000056061402045477700204150ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock, patch from setools import SELinuxPolicy from setools.exception import InvalidInitialSid @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.context.context_factory', lambda x, y: y) class InitialSIDTest(unittest.TestCase): @staticmethod def mock_sid(name): sid = Mock(qpol.qpol_isid_t) sid.name.return_value = name sid.context.return_value = name + "_context" return sid @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/initsid.conf") def test_001_factory(self): """InitialSID: factory on qpol object.""" q = self.mock_sid("test1") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test1", sid.qpol_symbol.name(self.p.policy)) def test_002_factory_object(self): """InitialSID: factory on InitialSID object.""" q = self.mock_sid("test2") sid1 = initialsid_factory(self.p.policy, q) sid2 = initialsid_factory(self.p.policy, sid1) self.assertIs(sid2, sid1) def test_003_factory_lookup(self): """InitialSID: factory lookup.""" sid = initialsid_factory(self.p.policy, "kernel") self.assertEqual("kernel", sid.qpol_symbol.name(self.p.policy)) def test_004_factory_lookup_invalid(self): """InitialSID: factory lookup.""" with self.assertRaises(InvalidInitialSid): initialsid_factory(self.p.policy, "INVALID") def test_010_string(self): """InitialSID: basic string rendering.""" q = self.mock_sid("test10") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test10", str(sid)) def test_020_statement(self): """InitialSID: context.""" q = self.mock_sid("test20") sid = initialsid_factory(self.p.policy, q) self.assertEqual("test20_context", sid.context) def test_030_statement(self): """InitialSID: statement.""" q = self.mock_sid("test30") sid = initialsid_factory(self.p.policy, q) self.assertEqual("sid test30 test30_context", sid.statement()) setools-4.4.0/tests/policyrep/invalid_policies/000077500000000000000000000000001402045477700217065ustar00rootroot00000000000000setools-4.4.0/tests/policyrep/invalid_policies/nodecon-invalid-range.conf000066400000000000000000000044011402045477700267170ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # Booleans Query # # test 1 # name: test1 # default: unset bool test1 true; # test 2 # name: test2(a|b) regex # default: unset bool test2a true; bool test2b true; # test 10 # name: unset # default: false; bool test10a false; bool test10b false; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here # this is an invalid context (invalid range) nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:elsewhere setools-4.4.0/tests/policyrep/invalid_policies/user-level-not-in-range.conf000066400000000000000000000122311402045477700271330ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class removed_class class modified_add_perm class modified_remove_perm class modified_change_common sid kernel sid security sid matched_sid sid removed_sid sid modified_sid common infoflow { low_w med_w hi_w low_r med_r hi_r } common removed_common { old_com } common modified_remove_perm { same_perm removed_perm } common modified_add_perm { matched_perm } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class removed_class { null_perm } class modified_add_perm { same_perm } class modified_remove_perm { same_perm removed_perm } class modified_change_common inherits removed_common sensitivity s0 alias { al1 al2 }; sensitivity s1 alias { al3 }; sensitivity s2; sensitivity s3; sensitivity s40; sensitivity s41; sensitivity s42; sensitivity s43; sensitivity s44; sensitivity s45; sensitivity s47; dominance { s0 s1 s2 s3 s40 s41 s42 s43 s44 s45 s47 } category c0 alias { spam eggs }; category c1 alias { bar }; category c2; category c3; category c4; category c5; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s40:c1; level s41:c0.c4; level s42:c0.c4; level s43:c0.c4; level s44:c0.c4; level s45:c0.c4; level s47:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute an_attr; attribute removed_attr; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules type removed_type; type modified_remove_attr, an_attr; type modified_remove_alias alias an_alias; type modified_remove_permissive; permissive modified_remove_permissive; type modified_add_attr; type modified_add_alias; type modified_add_permissive; role removed_role; role modified_add_type; role modified_remove_type; role modified_remove_type types { system }; # booleans bool same_bool true; bool removed_bool true; bool modified_bool false; ################################################################################ # policycaps policycap open_perms; policycap network_peer_controls; #users user system roles system level s0 range s0; user removed_user roles system level s0 range s0; user modified_add_role roles system level s2 range s2; user modified_remove_role roles { system removed_role } level s2 range s2; user modified_change_level roles system level s2:c0 range s2:c0 - s2:c0,c1; # this is an invalid user: default level is not within the range. user modified_change_range roles system level s3:c1 range s3:c1.c3; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 sid matched_sid system:system:system:s0 sid removed_sid removed_user:system:system:s0 sid modified_sid system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; fs_use_task removed_fsuse system:object_r:system:s0; fs_use_trans modified_fsuse removed_user:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s0 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s0 genfscon removed_genfs / system:object_r:system:s0 genfscon change_path /old system:object_r:system:s0 genfscon modified_genfs / -s removed_user:object_r:system:s0 # matched portcons portcon tcp 80 system:object_r:system:s0 portcon udp 80 system:object_r:system:s0 portcon udp 30-40 system:object_r:system:s0 # removed portcons portcon udp 1024 system:object_r:system:s0 portcon tcp 1024-1026 system:object_r:system:s0 # modified portcons portcon udp 3024 removed_user:object_r:system:s0 portcon tcp 3024-3026 removed_user:object_r:system:s0 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 netifcon removed_netif system:object_r:system:s0 system:object_r:system:s0 netifcon mod_ctx_netif removed_user:object_r:system:s0 system:object_r:system:s0 netifcon mod_pkt_netif system:object_r:system:s0 removed_user:object_r:system:s0 netifcon mod_both_netif removed_user:object_r:system:s0 removed_user:object_r:system:s0 # matched nodecons nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 # removed nodecons nodecon 127.0.0.2 255.255.255.255 removed_user:object_r:system:s0 nodecon ::2 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff removed_user:object_r:system:s0 # modified nodecons nodecon 127.0.0.3 255.255.255.255 modified_change_level:object_r:system:s2:c1 nodecon ::3 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff modified_change_level:object_r:system:s2:c0,c1 # change netmask (add/remove) nodecon 127.0.0.5 255.255.255.255 system:object_r:system:s0 nodecon ::5 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/mls.conf000066400000000000000000000044401402045477700200350ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } 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; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/mls.py000066400000000000000000000740261402045477700175470ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock from setools import SELinuxPolicy from setools.exception import MLSDisabled, InvalidLevel, InvalidLevelDecl, InvalidRange, \ InvalidSensitivity, InvalidCategory, NoStatement @unittest.skip("Needs to be reworked for cython") class SensitivityTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_sens_factory(self, sens, aliases=[]): """Factory function for Sensitivity objects, using a mock qpol object.""" mock_sens = Mock(qpol.qpol_level_t) mock_sens.name.return_value = sens mock_sens.isalias.return_value = False mock_sens.value.return_value = int(sens[1:]) mock_sens.alias_iter = lambda x: iter(aliases) return sensitivity_factory(self.p.policy, mock_sens) def test_000_mls_disabled(self): """Sensitivity factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, sensitivity_factory, mock_p, None) def test_001_lookup(self): """Sensitivity factory policy lookup.""" sens = sensitivity_factory(self.p.policy, "s1") self.assertEqual("s1", sens.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Sensitivity factory policy invalid lookup.""" with self.assertRaises(InvalidSensitivity): sensitivity_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Sensitivity factory policy lookup of Sensitivity object.""" sens1 = sensitivity_factory(self.p.policy, "s1") sens2 = sensitivity_factory(self.p.policy, sens1) self.assertIs(sens2, sens1) def test_010_string(self): """Sensitivity basic string rendering.""" sens = self.mock_sens_factory("s0") self.assertEqual("s0", str(sens)) def test_020_statement(self): """Sensitivity basic statement rendering.""" sens = self.mock_sens_factory("s0") self.assertEqual("sensitivity s0;", sens.statement()) def test_021_statement_alias(self): """Sensitivity one alias statement rendering.""" sens = self.mock_sens_factory("s0", ["name1"]) self.assertEqual("sensitivity s0 alias name1;", sens.statement()) def test_022_statement_alias(self): """Sensitivity two alias statement rendering.""" sens = self.mock_sens_factory("s0", ["name1", "name2"]) self.assertEqual("sensitivity s0 alias { name1 name2 };", sens.statement()) def test_030_value(self): """Sensitivity value.""" sens = self.mock_sens_factory("s17") self.assertEqual(17, sens._value) def test_031_equal(self): """Sensitivity equal.""" sens1 = self.mock_sens_factory("s0") sens2 = self.mock_sens_factory("s0") self.assertEqual(sens1, sens2) def test_032_equal_str(self): """Sensitivity equal to string.""" sens = self.mock_sens_factory("s17") self.assertEqual("s17", sens) def test_033_not_equal(self): """Sensitivity not equal.""" sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertNotEqual(sens1, sens2) def test_034_not_equal_str(self): """Sensitivity not equal to string.""" sens = self.mock_sens_factory("s17") self.assertNotEqual("s0", sens) def test_035_lt(self): """Sensitivity less-than.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertTrue(sens1 < sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertFalse(sens1 < sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertFalse(sens1 < sens2) def test_036_le(self): """Sensitivity less-than-or-equal.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertTrue(sens1 <= sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertTrue(sens1 <= sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertFalse(sens1 <= sens2) def test_037_ge(self): """Sensitivity greater-than-or-equal.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertFalse(sens1 >= sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertTrue(sens1 >= sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertTrue(sens1 >= sens2) def test_038_gt(self): """Sensitivity greater-than.""" # less sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s23") self.assertFalse(sens1 > sens2) # equal sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s17") self.assertFalse(sens1 > sens2) # greater sens1 = self.mock_sens_factory("s17") sens2 = self.mock_sens_factory("s0") self.assertTrue(sens1 > sens2) @unittest.skip("Needs to be reworked for cython") class CategoryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_cat_factory(self, cat, aliases=[]): """Factory function for Category objects, using a mock qpol object.""" mock_cat = Mock(qpol.qpol_cat_t) mock_cat.name.return_value = cat mock_cat.isalias.return_value = False mock_cat.value.return_value = int(cat[1:]) mock_cat.alias_iter = lambda x: iter(aliases) return category_factory(self.p.policy, mock_cat) def test_000_mls_disabled(self): """Category factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, category_factory, mock_p, None) def test_001_lookup(self): """Category factory policy lookup.""" cat = category_factory(self.p.policy, "c1") self.assertEqual("c1", cat.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Category factory policy invalid lookup.""" with self.assertRaises(InvalidCategory): category_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Category factory policy lookup of Category object.""" cat1 = category_factory(self.p.policy, "c1") cat2 = category_factory(self.p.policy, cat1) self.assertIs(cat2, cat1) def test_010_statement(self): """Category basic string rendering.""" cat = self.mock_cat_factory("c0") self.assertEqual("c0", str(cat)) def test_020_statement(self): """Category basic statement rendering.""" cat = self.mock_cat_factory("c0") self.assertEqual("category c0;", cat.statement()) def test_021_statement_alias(self): """Category one alias statement rendering.""" cat = self.mock_cat_factory("c0", ["name1"]) self.assertEqual("category c0 alias name1;", cat.statement()) def test_022_statement_alias(self): """Category two alias statement rendering.""" cat = self.mock_cat_factory("c0", ["name1", "name2"]) self.assertEqual("category c0 alias { name1 name2 };", cat.statement()) def test_030_value(self): """Category value.""" cat = self.mock_cat_factory("c17") self.assertEqual(17, cat._value) @unittest.skip("Needs to be reworked for cython") class LevelDeclTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_decl_factory(self, sens, cats=[]): """Factory function for LevelDecl objects, using a mock qpol object.""" mock_decl = Mock(qpol.qpol_level_t) mock_decl.name.return_value = sens mock_decl.isalias.return_value = False mock_decl.value.return_value = int(sens[1:]) mock_decl.cat_iter = lambda x: iter(cats) return level_decl_factory(self.p.policy, mock_decl) def test_000_mls_disabled(self): """Level declaration factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, level_decl_factory, mock_p, None) def test_001_lookup(self): """Level declaration factory policy lookup.""" decl = level_decl_factory(self.p.policy, "s1") self.assertEqual("s1", decl.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Level declaration factory policy invalid lookup.""" with self.assertRaises(InvalidLevelDecl): level_decl_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Level declaration factory policy lookup of LevelDecl object.""" level1 = level_decl_factory(self.p.policy, "s1") level2 = level_decl_factory(self.p.policy, level1) self.assertIs(level2, level1) def test_010_string(self): """Level declaration basic string rendering.""" decl = self.mock_decl_factory("s0") self.assertEqual("s0", str(decl)) def test_011_string_single_cat(self): """Level declaration string rendering with one category""" decl = self.mock_decl_factory("s0", ["c0"]) self.assertEqual("s0:c0", str(decl)) def test_012_string_multiple_cat(self): """Level declaration string rendering with multiple categories""" decl = self.mock_decl_factory("s0", ["c0", "c3"]) self.assertEqual("s0:c0,c3", str(decl)) def test_013_string_cat_set(self): """Level declaration string rendering with category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual("s0:c0.c3", str(decl)) def test_014_string_complex(self): """Level declaration string rendering with complex category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3", "c5", "c7", "c8", "c9"]) self.assertEqual("s0:c0.c3,c5,c7.c9", str(decl)) def test_020_statement(self): """Level declaration basic statement rendering.""" decl = self.mock_decl_factory("s0") self.assertEqual("level s0;", decl.statement()) def test_021_statement_single_cat(self): """Level declaration statement rendering with one category""" decl = self.mock_decl_factory("s0", ["c0"]) self.assertEqual("level s0:c0;", decl.statement()) def test_022_statement_multiple_cat(self): """Level declaration statement rendering with multiple categories""" decl = self.mock_decl_factory("s0", ["c0", "c3"]) self.assertEqual("level s0:c0,c3;", decl.statement()) def test_012_string_cat_set(self): """Level declaration statement rendering with category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual("level s0:c0.c3;", decl.statement()) def test_013_statement_complex(self): """Level declaration statement rendering with complex category set""" decl = self.mock_decl_factory("s0", ["c0", "c1", "c2", "c3", "c5", "c7", "c8", "c9"]) self.assertEqual("level s0:c0.c3,c5,c7.c9;", decl.statement()) def test_030_equal(self): """Level declaration equal.""" decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertEqual(decl1, decl2) def test_031_equal_str(self): """Level declaration equal to string.""" decl = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertEqual("s17:c0.c3", decl) def test_032_not_equal(self): """Level declaration not equal.""" decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23") self.assertNotEqual(decl1, decl2) def test_033_not_equal_str(self): """Level declaration not equal to string.""" decl = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertNotEqual("s0:c0.c2", decl) def test_034_lt(self): """Level declaration less-than.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 < decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertFalse(decl1 < decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 < decl2) def test_035_le(self): """Level declaration less-than-or-equal.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 <= decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertTrue(decl1 <= decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 <= decl2) def test_036_ge(self): """Level declaration greater-than-or-equal.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 >= decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertTrue(decl1 >= decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 >= decl2) def test_037_gt(self): """Level declaration greater-than.""" # less decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertFalse(decl1 > decl2) # equal decl1 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) decl2 = self.mock_decl_factory("s17", ["c0", "c1", "c2", "c3"]) self.assertFalse(decl1 > decl2) # greater decl1 = self.mock_decl_factory("s24") decl2 = self.mock_decl_factory("s23", ["c7", "c8", "c9"]) self.assertTrue(decl1 > decl2) @unittest.skip("Needs to be reworked for cython") class LevelTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def mock_level_factory(self, sens, cats=[]): """Factory function Level objects, using a mock qpol object.""" mock_level = Mock(qpol.qpol_mls_level_t) mock_level.sens_name.return_value = sens mock_level.cat_iter = lambda x: iter(cats) return level_factory(self.p.policy, mock_level) def test_000_mls_disabled(self): """Level factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, level_factory, mock_p, None) def test_001_lookup_no_cats(self): """Level lookup with no categories.""" levelobj = level_factory(self.p.policy, "s2") self.assertEqual("s2", levelobj.qpol_symbol.sens_name(self.p.policy)) self.assertEqual(str(levelobj), "s2") def test_002_lookup_cat_range(self): """Level lookup with category range.""" levelobj = level_factory(self.p.policy, "s1:c0.c13") self.assertEqual(str(levelobj), "s1:c0.c13") def test_003_lookup_complex_cats(self): """Level lookup with complex category set.""" levelobj = level_factory(self.p.policy, "s2:c0.c5,c7,c9.c11,c13") self.assertEqual(str(levelobj), "s2:c0.c5,c7,c9.c11,c13") def test_004_lookup_bad1(self): """Level lookup with garbage.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL") def test_005_lookup_bad2(self): """Level lookup with : in garbage.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "FAIL:BAD") def test_006_lookup_bad_cat(self): """Level lookup with invalid category.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:FAIL") def test_007_lookup_bad_cat_range(self): """Level lookup with backwards category range.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c4.c0") def test_008_lookup_cat_range_error(self): """Level lookup with category range parse error.""" self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0.c2.c4") def test_009_lookup_cat_not_assoc(self): """Level lookup with category not associated with sensitivity.""" # c4 is not associated with s0. self.assertRaises(InvalidLevel, level_factory, self.p.policy, "s0:c0,c4") def test_00a_lookup_object(self): """Level factory policy lookup of Level object.""" level1 = level_factory(self.p.policy, "s0") level2 = level_factory(self.p.policy, level1) self.assertIs(level2, level1) def test_010_equal(self): """Level equal.""" level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) self.assertEqual(level1, level2) def test_011_equal_str(self): """Level equal to string.""" level = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) self.assertEqual("s2:c0.c3", level) def test_012_not_equal(self): """Level not equal.""" level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s0") self.assertNotEqual(level1, level2) def test_013_not_equal_str(self): """Level not equal to string.""" level = self.mock_level_factory("s0", ["c0", "c2"]) self.assertNotEqual("s0:c0.c2", level) def test_014_dom(self): """Level dominate (ge).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 >= level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 >= level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 >= level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 >= level2) def test_015_domby(self): """Level dominate-by (le).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 <= level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 <= level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 <= level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 <= level2) def test_016_proper_dom(self): """Level proper dominate (gt).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 > level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 > level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 > level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 > level2) def test_017_proper_domby(self): """Level proper dominate-by (lt).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 < level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 < level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertTrue(level1 < level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertFalse(level1 < level2) def test_018_incomp(self): """Level incomparable (xor).""" # equal level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # sens dominate level1 = self.mock_level_factory("s2", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # cat set dominate level1 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3", "c4"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # sens domby level1 = self.mock_level_factory("s0", ["c0", "c1", "c2", "c3"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # cat set domby level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c0", "c1", "c2", "c3"]) self.assertFalse(level1 ^ level2) # incomp level1 = self.mock_level_factory("s1", ["c0", "c1", "c2"]) level2 = self.mock_level_factory("s1", ["c7", "c8", "c9"]) self.assertTrue(level1 ^ level2) def test_020_level_statement(self): """Level has no statement.""" level = self.mock_level_factory("s1") with self.assertRaises(NoStatement): level.statement() @unittest.skip("Needs to be reworked for cython") class RangeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/mls.conf") def test_000_mls_disabled(self): """Range factory on MLS-disabled policy.""" mock_p = Mock(qpol.qpol_policy_t) mock_p.capability.return_value = False self.assertRaises(MLSDisabled, range_factory, mock_p, None) def test_001_range_lookup_single_level(self): """Range lookup with single-level range.""" rangeobj = range_factory(self.p.policy, "s0") self.assertEqual(str(rangeobj), "s0") def test_002_range_lookup_single_level_redundant(self): """Range lookup with single-level range (same range listed twice).""" rangeobj = range_factory(self.p.policy, "s1-s1") self.assertEqual(str(rangeobj), "s1") def test_003_range_lookup_simple(self): """Range lookup with simple range.""" rangeobj = range_factory(self.p.policy, "s0-s1:c0.c10") self.assertEqual(str(rangeobj), "s0 - s1:c0.c10") def test_004_range_lookup_no_cats(self): """Range lookup with no categories.""" rangeobj = range_factory(self.p.policy, "s0-s1") self.assertEqual(str(rangeobj), "s0 - s1") def test_005_range_lookup_complex(self): """Range lookup with complex category set.""" rangeobj = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual(str(rangeobj), "s0:c0.c2 - s2:c0.c5,c7,c9.c11,c13") def test_006_range_lookup_non_dom(self): """Range lookup with non-dominating high level.""" self.assertRaises(InvalidRange, range_factory, self.p.policy, "s1-s0") def test_007_range_lookup_invalid_range_low(self): """Range lookup with an invalid range (low).""" # c13 is not associated with s0. self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0:c13-s2:c13") def test_008_range_lookup_invalid_range_high(self): """Range lookup with an invalid range (high).""" # c13 is not associated with s0. self.assertRaises(InvalidRange, range_factory, self.p.policy, "s0-s0:c13") def test_009_lookup_object(self): """Range factory policy lookup of Range object.""" range1 = range_factory(self.p.policy, "s0") range2 = range_factory(self.p.policy, range1) self.assertIs(range2, range1) def test_020_equal(self): """Range equality.""" rangeobj1 = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") rangeobj2 = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual(rangeobj1, rangeobj2) def test_021_equal(self): """Range equal to string.""" rangeobj = range_factory(self.p.policy, "s0:c0.c2-s2:c0.c5,c7,c9.c11,c13") self.assertEqual("s0:c0.c2-s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2- s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2 -s2:c0.c5,c7,c9.c11,c13", rangeobj) self.assertEqual("s0:c0.c2 - s2:c0.c5,c7,c9.c11,c13", rangeobj) def test_022_contains(self): """Range contains a level.""" rangeobj = range_factory(self.p.policy, "s0:c1-s2:c0.c10") # too low level1 = level_factory(self.p.policy, "s0") self.assertNotIn(level1, rangeobj) # low level level2 = level_factory(self.p.policy, "s0:c1") self.assertIn(level2, rangeobj) # mid level3 = level_factory(self.p.policy, "s1:c1,c5") self.assertIn(level3, rangeobj) # high level level4 = level_factory(self.p.policy, "s2:c0.c10") self.assertIn(level4, rangeobj) # too high level5 = level_factory(self.p.policy, "s2:c0.c11") self.assertNotIn(level5, rangeobj) def test_030_range_statement(self): """Range has no statement.""" rangeobj = range_factory(self.p.policy, "s0") with self.assertRaises(NoStatement): rangeobj.statement() setools-4.4.0/tests/policyrep/mlsrule.py000066400000000000000000000073241402045477700204340ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import unittest from unittest.mock import Mock, patch from setools import MLSRuletype as MRT from setools.exception import InvalidMLSRuleType, RuleNotConditional @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.mls.range_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class MLSRuleTest(unittest.TestCase): def mock_rangetrans_factory(self, source, target, tclass, default): mock_rule = Mock(qpol_range_trans_t) mock_rule.rule_type.return_value = MRT.range_transition mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.range.return_value = default return mls_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RangeTransition factory lookup.""" with self.assertRaises(TypeError): mls_rule_factory(self.p, "INVALID") def test_001_validate_ruletype(self): """RangeTransition valid rule types.""" self.assertEqual(MRT.range_transition, validate_ruletype("range_transition")) @unittest.skip("MLS ruletype changed to an enumeration.") def test_002_validate_ruletype_invalid(self): """RangeTransition valid rule types.""" with self.assertRaises(InvalidMLSRuleType): self.assertTrue(validate_ruletype("type_transition")) def test_010_ruletype(self): """RangeTransition rule type""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") self.assertEqual(MRT.range_transition, rule.ruletype) def test_020_source_type(self): """RangeTransition source type""" rule = self.mock_rangetrans_factory("source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """RangeTransition target type""" rule = self.mock_rangetrans_factory("a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RangeTransition object class""" rule = self.mock_rangetrans_factory("a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_default(self): """RangeTransition default range""" rule = self.mock_rangetrans_factory("a", "b", "c", "default50") self.assertEqual("default50", rule.default) def test_060_conditional(self): """RangeTransition conditional expression""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_100_statement(self): """RangeTransition statement.""" rule = self.mock_rangetrans_factory("a", "b", "c", "d") self.assertEqual("range_transition a b:c d;", rule.statement()) setools-4.4.0/tests/policyrep/objclass.conf000066400000000000000000000040461402045477700210440ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class infoflow8 class infoflow9 class infoflow10 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } common com_a { hi_w hi_r super_r super_w } common com_b { send recv } common com_c { getattr setattr read write } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow { super_w super_r super_none super_both super_unmapped } class infoflow5 inherits com_a class infoflow6 inherits com_b class infoflow7 inherits infoflow { unmapped } class infoflow8 { super_w super_r } class infoflow9 inherits com_c class infoflow10 { read write } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/policyrep/objclass.py000066400000000000000000000144711402045477700205520ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock from setools import SELinuxPolicy from setools.exception import InvalidCommon, InvalidClass @unittest.skip("Needs to be reworked for cython") class CommonTest(unittest.TestCase): @staticmethod def mock_common(name, perms): policy = Mock(qpol.qpol_policy_t) com = Mock(qpol.qpol_common_t) com.name.return_value = name com.perm_iter = lambda x: iter(perms) return common_factory(policy, com) @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/objclass.conf") def test_001_lookup(self): """Common: factory policy lookup.""" com = common_factory(self.p.policy, "com_a") self.assertEqual("com_a", com.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Common: factory policy invalid lookup.""" with self.assertRaises(InvalidCommon): common_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Common: factory policy lookup of Common object.""" com1 = common_factory(self.p.policy, "com_b") com2 = common_factory(self.p.policy, com1) self.assertIs(com2, com1) def test_010_string(self): """Common: string representation""" com = self.mock_common("test10", ["perm1", "perm2"]) self.assertEqual("test10", str(com)) def test_020_perms(self): """Common: permissions""" com = self.mock_common("test20", ["perm1", "perm2"]) self.assertEqual(set(["perm1", "perm2"]), com.perms) def test_030_statment(self): """Common: statement.""" com = self.mock_common("test30", ["perm1", "perm2"]) self.assertRegex(com.statement(), "(" "common test30\n{\n\tperm1\n\tperm2\n}" "|" "common test30\n{\n\tperm2\n\tperm1\n}" ")") def test_040_contains(self): """Common: contains""" com = self.mock_common("test40", ["perm1", "perm2"]) self.assertIn("perm1", com) self.assertNotIn("perm3", com) @unittest.skip("Needs to be reworked for cython") class ObjClassTest(unittest.TestCase): @staticmethod def mock_class(name, perms, com_perms=[]): policy = Mock(qpol.qpol_policy_t) cls = Mock(qpol.qpol_class_t) cls.name.return_value = name cls.perm_iter = lambda x: iter(perms) if com_perms: com = Mock(qpol.qpol_common_t) com.name.return_value = name + "_common" com.perm_iter = lambda x: iter(com_perms) cls.common.return_value = com else: cls.common.side_effect = ValueError return class_factory(policy, cls) @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/objclass.conf") def test_001_lookup(self): """ObjClass: factory policy lookup.""" cls = class_factory(self.p.policy, "infoflow") self.assertEqual("infoflow", cls.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """ObjClass: factory policy invalid lookup.""" with self.assertRaises(InvalidClass): class_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """ObjClass: factory policy lookup of ObjClass object.""" cls1 = class_factory(self.p.policy, "infoflow4") cls2 = class_factory(self.p.policy, cls1) self.assertIs(cls2, cls1) def test_010_string(self): """ObjClass: string representation""" cls = self.mock_class("test10", ["perm1", "perm2"]) self.assertEqual("test10", str(cls)) def test_020_perms(self): """ObjClass: permissions""" cls = self.mock_class("test20", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertEqual(set(["perm1", "perm2"]), cls.perms) def test_030_statment(self): """ObjClass: statement, no common.""" cls = self.mock_class("test30", ["perm1", "perm2"]) self.assertRegex(cls.statement(), "(" "class test30\n{\n\tperm1\n\tperm2\n}" "|" "class test30\n{\n\tperm2\n\tperm1\n}" ")") def test_031_statment(self): """ObjClass: statement, with common.""" cls = self.mock_class("test31", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertRegex(cls.statement(), "(" "class test31\ninherits test31_common\n{\n\tperm1\n\tperm2\n}" "|" "class test31\ninherits test31_common\n{\n\tperm2\n\tperm1\n}" ")") def test_032_statment(self): """ObjClass: statement, with common, no class perms.""" cls = self.mock_class("test32", [], com_perms=["perm3", "perm4"]) self.assertRegex(cls.statement(), "(" "class test32\ninherits test32_common" "|" "class test32\ninherits test32_common" ")") def test_040_contains(self): """ObjClass: contains""" cls = self.mock_class("test40", ["perm1", "perm2"]) self.assertIn("perm1", cls) self.assertNotIn("perm3", cls) def test_041_contains_common(self): """ObjClass: contains, with common""" cls = self.mock_class("test41", ["perm1", "perm2"], com_perms=["perm3", "perm4"]) self.assertIn("perm1", cls) self.assertIn("perm3", cls) self.assertNotIn("perm5", cls) setools-4.4.0/tests/policyrep/polcap.py000066400000000000000000000041371402045477700202260ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import unittest from unittest.mock import Mock @unittest.skip("Needs to be reworked for cython") class PolCapTest(unittest.TestCase): @staticmethod def mock_cap(name): cap = Mock(qpol.qpol_polcap_t) cap.name.return_value = name return cap def setUp(self): self.p = Mock(qpol.qpol_policy_t) def test_001_factory(self): """PolCap: factory on qpol object.""" q = self.mock_cap("test1") cap = polcap_factory(self.p, q) self.assertEqual("test1", cap.qpol_symbol.name(self.p)) def test_002_factory_object(self): """PolCap: factory on PolCap object.""" q = self.mock_cap("test2") cap1 = polcap_factory(self.p, q) cap2 = polcap_factory(self.p, cap1) self.assertIs(cap2, cap1) def test_003_factory_lookup(self): """PolCap: factory lookup.""" with self.assertRaises(TypeError): polcap_factory(self.p, "open_perms") def test_010_string(self): """PolCap: basic string rendering.""" q = self.mock_cap("test10") cap = polcap_factory(self.p, q) self.assertEqual("test10", str(cap)) def test_020_statement(self): """PolCap: statement.""" q = self.mock_cap("test20") cap = polcap_factory(self.p, q) self.assertEqual("policycap test20;", cap.statement()) setools-4.4.0/tests/policyrep/rbacrule.py000066400000000000000000000141131402045477700205420ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import unittest from unittest.mock import Mock, patch from setools.exception import InvalidRBACRuleType, RuleNotConditional, RuleUseError @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.role.role_factory', lambda x, y: y) class RoleAllowTest(unittest.TestCase): def mock_avrule_factory(self, source, target): mock_rule = Mock(qpol_role_allow_t) mock_rule.rule_type.return_value = RBACRuletype.allow mock_rule.source_role.return_value = source mock_rule.target_role.return_value = target return rbac_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RoleAllow factory lookup.""" with self.assertRaises(TypeError): rbac_rule_factory(self.p, "INVALID") @unittest.skip("RBAC ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """RoleAllow valid rule types.""" # no return value means a return of None self.assertEqual("allow", validate_ruletype("allow")) def test_002_validate_ruletype_invalid(self): """RoleAllow valid rule types.""" with self.assertRaises(InvalidRBACRuleType): self.assertTrue(validate_ruletype("range_transition")) def test_010_ruletype(self): """RoleAllow rule type""" rule = self.mock_avrule_factory("a", "b") self.assertEqual(RBACRuletype.allow, rule.ruletype) def test_020_source_role(self): """RoleAllow source role""" rule = self.mock_avrule_factory("source20", "b") self.assertEqual("source20", rule.source) def test_030_target_role(self): """RoleAllow target role""" rule = self.mock_avrule_factory("a", "target30") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RoleAllow object class""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleUseError): rule.tclass def test_060_conditional(self): """RoleAllow conditional expression""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """RoleAllow default role""" rule = self.mock_avrule_factory("a", "b") with self.assertRaises(RuleUseError): rule.default def test_100_statement_one_perm(self): """RoleAllow statement.""" rule = self.mock_avrule_factory("a", "b") self.assertEqual("allow a b;", rule.statement()) @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.role.role_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class RoleTransitionTest(unittest.TestCase): def mock_roletrans_factory(self, source, target, tclass, default): mock_rule = Mock(qpol_role_trans_t) mock_rule.rule_type.return_value = RBACRuletype.role_transition mock_rule.source_role.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.default_role.return_value = default return rbac_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """RoleTransition factory lookup.""" with self.assertRaises(TypeError): rbac_rule_factory(self.p, "INVALID") def test_001_validate_ruletype(self): """RoleTransition valid rule types.""" self.assertEqual(RBACRuletype.role_transition, validate_ruletype("role_transition")) def test_002_validate_ruletype_invalid(self): """RoleTransition valid rule types.""" with self.assertRaises(InvalidRBACRuleType): self.assertTrue(validate_ruletype("type_transition")) def test_010_ruletype(self): """RoleTransition rule type""" rule = self.mock_roletrans_factory("a", "b", "c", "d") self.assertEqual(RBACRuletype.role_transition, rule.ruletype) def test_020_source_role(self): """RoleTransition source role""" rule = self.mock_roletrans_factory("source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """RoleTransition target type""" rule = self.mock_roletrans_factory("a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """RoleTransition object class""" rule = self.mock_roletrans_factory("a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_default(self): """RoleTransition default role""" rule = self.mock_roletrans_factory("a", "b", "c", "default50") self.assertEqual("default50", rule.default) def test_060_conditional(self): """RoleTransition conditional expression""" rule = self.mock_roletrans_factory("a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_100_statement(self): """RoleTransition statement.""" rule = self.mock_roletrans_factory("a", "b", "c", "d") self.assertEqual("role_transition a b:c d;", rule.statement()) setools-4.4.0/tests/policyrep/role.conf000066400000000000000000000044401402045477700202030ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } 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; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/role.py000066400000000000000000000066251402045477700177150ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock from setools import SELinuxPolicy from setools.exception import InvalidRole @unittest.skip("Needs to be reworked for cython") class RoleTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/role.conf") def mock_role_factory(self, name, types): """Factory function for Role objects, using a mock qpol object.""" mock_role = Mock(qpol.qpol_role_t) mock_role.name.return_value = name mock_role.type_iter = lambda x: iter(types) return role_factory(self.p.policy, mock_role) def test_001_lookup(self): """Role factory policy lookup.""" role = role_factory(self.p.policy, "role20_r") self.assertEqual("role20_r", role.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Role factory policy invalid lookup.""" with self.assertRaises(InvalidRole): role_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """Role factory policy lookup of Role object.""" role1 = role_factory(self.p.policy, "role20_r") role2 = role_factory(self.p.policy, role1) self.assertIs(role2, role1) def test_010_string(self): """Role basic string rendering.""" role = self.mock_role_factory("rolename10", ['type1']) self.assertEqual("rolename10", str(role)) def test_020_statement_type(self): """Role statement, one type.""" role = self.mock_role_factory("rolename20", ['type30']) self.assertEqual("role rolename20 types type30;", role.statement()) def test_021_statement_two_types(self): """Role statement, two types.""" role = self.mock_role_factory("rolename21", ['type31a', 'type31b']) self.assertEqual("role rolename21 types { type31a type31b };", role.statement()) def test_022_statement_decl(self): """Role statement, no types.""" # This is an unlikely corner case, where a role # has been declared but has no types. role = self.mock_role_factory("rolename22", []) self.assertEqual("role rolename22;", role.statement()) def test_030_types(self): """Role types generator.""" role = self.mock_role_factory("rolename", ['type31b', 'type31c']) self.assertEqual(['type31b', 'type31c'], sorted(role.types())) def test_040_expand(self): """Role expansion""" role = self.mock_role_factory("rolename", ['type31a', 'type31b', 'type31c']) expanded = list(role.expand()) self.assertEqual(1, len(expanded)) self.assertIs(role, expanded[0]) setools-4.4.0/tests/policyrep/selinuxpolicy.conf000066400000000000000000004321571402045477700221630ustar00rootroot00000000000000# 7 classes class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 # 11 SIDs sid sid_one sid sid_two sid sid_three sid sid_four sid sid_five sid sid_six sid sid_seven sid sid_eight sid sid_nine sid sid_ten sid sid_eleven # 3 commons common low_c { low_w low_r low_none } common med_c { med_w med_r med_none med_both med_fifth } common hi_c { hi_w hi_r hi_third hi_fourth hi_fifth hi_sixth hi_seventh } # 7 classes # 29 permissions (common perms are only counted once) class infoflow inherits low_c class infoflow2 inherits med_c { super_w super_r } class infoflow3 { null } class infoflow4 inherits hi_c { super_both } class infoflow5 inherits hi_c class infoflow6 { ioctl dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable } class infoflow7 inherits hi_c # 13 sensitivities/levels sensitivity s0 alias sens_alias0; sensitivity s1 alias sens_alias1; sensitivity s2 alias sens_alias2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; sensitivity s7; sensitivity s8; sensitivity s9; sensitivity s10; sensitivity s11; sensitivity s12; dominance { s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 } # 17 categories category c0 alias cat_alias0; category c1 alias cat_alias1; category c2 alias cat_alias2; 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; # 13 levels level s0:c0.c1; level s1:c0.c3; level s2:c0.c5; level s3:c0.c7; level s4:c0.c10; level s5:c0.c7; level s6:c0.c5; level s7:c0.c5; level s8:c0.c5; level s9:c0.c5; level s10:c0.c5; level s11:c0.c5; level s12:c0.c16; # 23 MLS constraints mlsconstrain infoflow low_w ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow low_r ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow low_none ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow2 med_r ((l1 eq l2) or (t1 == attr1)); mlsconstrain infoflow2 med_w ((h1 dom l2) or (t1 == attr1)); mlsconstrain infoflow2 med_none ((h1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow2 med_both ((h1 domby l2) or (t1 == attr1)); mlsconstrain infoflow2 med_fifth ((h1 eq l2) or (t1 == attr1)); mlsconstrain infoflow2 super_r ((l1 incomp h2) or (t1 == attr1)); mlsconstrain infoflow2 super_w ((l1 eq h2) or (t1 == attr1)); mlsconstrain infoflow4 hi_w ((h1 dom l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_r ((h1 domby l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_third ((h1 eq l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_fourth ((h1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_fifth ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_sixth ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow4 hi_seventh ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow4 super_both ((l1 eq l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_w ((l1 dom l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_r ((l1 domby l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_third ((l1 incomp l2) or (t1 == attr1)); mlsconstrain infoflow5 hi_fifth ((l1 dom h2) or (t1 == attr1)); mlsconstrain infoflow5 hi_sixth ((l1 domby h2) or (t1 == attr1)); # 3 mlsvalidatetrans mlsvalidatetrans { infoflow infoflow2 infoflow3 } ((l1 dom l2) or (t3 == attr1)); # 2 policycaps policycap open_perms; policycap network_peer_controls; attribute attr0; attribute attr1; attribute attr2; attribute attr3; attribute attr4; attribute attr5; attribute attr6; attribute attr7; attribute attr8; attribute attr9; attribute attr10; attribute attr11; attribute attr12; attribute attr13; attribute attr14; attribute attr15; attribute attr16; attribute attr17; attribute attr18; attribute attr19; attribute attr20; attribute attr21; attribute attr22; attribute attr23; attribute attr24; attribute attr25; attribute attr26; attribute attr27; attribute attr28; attribute attr29; attribute attr30; attribute attr31; attribute attr32; attribute attr33; attribute attr34; attribute attr35; attribute attr36; attribute attr37; attribute attr38; attribute attr39; attribute attr40; attribute attr41; attribute attr42; attribute attr43; attribute attr44; attribute attr45; attribute attr46; attribute attr47; attribute attr48; attribute attr49; attribute attr50; attribute attr51; attribute attr52; attribute attr53; attribute attr54; attribute attr55; attribute attr56; attribute attr57; attribute attr58; attribute attr59; attribute attr60; attribute attr61; attribute attr62; attribute attr63; attribute attr64; attribute attr65; attribute attr66; attribute attr67; attribute attr68; attribute attr69; attribute attr70; attribute attr71; attribute attr72; attribute attr73; attribute attr74; attribute attr75; attribute attr76; attribute attr77; attribute attr78; attribute attr79; attribute attr80; attribute attr81; attribute attr82; attribute attr83; attribute attr84; attribute attr85; attribute attr86; attribute attr87; attribute attr88; attribute attr89; attribute attr90; attribute attr91; attribute attr92; attribute attr93; attribute attr94; attribute attr95; attribute attr96; attribute attr97; attribute attr98; attribute attr99; attribute attr100; attribute attr101; attribute attr102; attribute attr103; attribute attr104; attribute attr105; attribute attr106; attribute attr107; attribute attr108; attribute attr109; attribute attr110; attribute attr111; attribute attr112; attribute attr113; attribute attr114; attribute attr115; attribute attr116; attribute attr117; attribute attr118; attribute attr119; attribute attr120; attribute attr121; attribute attr122; attribute attr123; attribute attr124; attribute attr125; attribute attr126; attribute attr127; attribute attr128; attribute attr129; attribute attr130; attribute attr131; attribute attr132; attribute attr133; attribute attr134; attribute attr135; attribute attr136; attribute attr137; attribute attr138; attribute attr139; attribute attr140; attribute attr141; attribute attr142; attribute attr143; attribute attr144; attribute attr145; attribute attr146; attribute attr147; attribute attr148; attribute attr149; attribute attr150; attribute attr151; attribute attr152; attribute attr153; attribute attr154; attribute attr155; attribute attr156; ################################################################################ # Type enforcement declarations and rules # 127 booleans bool bool0 true; bool bool1 true; bool bool2 true; bool bool3 true; bool bool4 true; bool bool5 true; bool bool6 true; bool bool7 true; bool bool8 true; bool bool9 true; bool bool10 true; bool bool11 true; bool bool12 true; bool bool13 true; bool bool14 true; bool bool15 true; bool bool16 true; bool bool17 true; bool bool18 true; bool bool19 true; bool bool20 true; bool bool21 true; bool bool22 true; bool bool23 true; bool bool24 true; bool bool25 true; bool bool26 true; bool bool27 true; bool bool28 true; bool bool29 true; bool bool30 true; bool bool31 true; bool bool32 true; bool bool33 true; bool bool34 true; bool bool35 true; bool bool36 true; bool bool37 true; bool bool38 true; bool bool39 true; bool bool40 true; bool bool41 true; bool bool42 true; bool bool43 true; bool bool44 true; bool bool45 true; bool bool46 true; bool bool47 true; bool bool48 true; bool bool49 true; bool bool50 true; bool bool51 true; bool bool52 true; bool bool53 true; bool bool54 true; bool bool55 true; bool bool56 true; bool bool57 true; bool bool58 true; bool bool59 true; bool bool60 true; bool bool61 true; bool bool62 true; bool bool63 true; bool bool64 true; bool bool65 true; bool bool66 true; bool bool67 true; bool bool68 true; bool bool69 true; bool bool70 true; bool bool71 true; bool bool72 true; bool bool73 true; bool bool74 true; bool bool75 true; bool bool76 true; bool bool77 true; bool bool78 true; bool bool79 true; bool bool80 true; bool bool81 true; bool bool82 true; bool bool83 true; bool bool84 true; bool bool85 true; bool bool86 true; bool bool87 true; bool bool88 true; bool bool89 true; bool bool90 true; bool bool91 true; bool bool92 true; bool bool93 true; bool bool94 true; bool bool95 true; bool bool96 true; bool bool97 true; bool bool98 true; bool bool99 true; bool bool100 true; bool bool101 true; bool bool102 true; bool bool103 true; bool bool104 true; bool bool105 true; bool bool106 true; bool bool107 true; bool bool108 true; bool bool109 true; bool bool110 true; bool bool111 true; bool bool112 true; bool bool113 true; bool bool114 true; bool bool115 true; bool bool116 true; bool bool117 true; bool bool118 true; bool bool119 true; bool bool120 true; bool bool121 true; bool bool122 true; bool bool123 true; bool bool124 true; bool bool125 true; bool bool126 true; # 131 roles # one less is declared here # because object_r is injected # by the compiler. role role0; role role1; role role2; role role3; role role4; role role5; role role6; role role7; role role8; role role9; role role10; role role11; role role12; role role13; role role14; role role15; role role16; role role17; role role18; role role19; role role20; role role21; role role22; role role23; role role24; role role25; role role26; role role27; role role28; role role29; role role30; role role31; role role32; role role33; role role34; role role35; role role36; role role37; role role38; role role39; role role40; role role41; role role42; role role43; role role44; role role45; role role46; role role47; role role48; role role49; role role50; role role51; role role52; role role53; role role54; role role55; role role56; role role57; role role58; role role59; role role60; role role61; role role62; role role63; role role64; role role65; role role66; role role67; role role68; role role69; role role70; role role71; role role72; role role73; role role74; role role75; role role76; role role77; role role78; role role79; role role80; role role81; role role82; role role83; role role84; role role85; role role86; role role87; role role88; role role89; role role90; role role91; role role92; role role93; role role94; role role95; role role96; role role97; role role98; role role99; role role100; role role101; role role102; role role103; role role104; role role105; role role106; role role107; role role108; role role109; role role110; role role111; role role112; role role113; role role114; role role115; role role116; role role117; role role118; role role119; role role120; role role121; role role122; role role123; role role124; role role125; role role126; role role127; role role128; role role129; role role0 types type0; role role1 types type0; role role2 types type0; role role3 types type0; role role4 types type0; role role5 types type0; role role6 types type0; role role7 types type0; role role8 types type0; role role9 types type0; role role10 types type0; role role11 types type0; role role12 types type0; role role13 types type0; role role14 types type0; role role15 types type0; role role16 types type0; role role17 types type0; role role18 types type0; role role19 types type0; role role20 types type0; role role21 types type0; role role22 types type0; role role23 types type0; role role24 types type0; role role25 types type0; role role26 types type0; role role27 types type0; role role28 types type0; role role29 types type0; role role30 types type0; role role31 types type0; role role32 types type0; role role33 types type0; role role34 types type0; role role35 types type0; role role36 types type0; role role37 types type0; role role38 types type0; role role39 types type0; role role40 types type0; role role41 types type0; role role42 types type0; role role43 types type0; role role44 types type0; role role45 types type0; role role46 types type0; role role47 types type0; role role48 types type0; role role49 types type0; role role50 types type0; role role51 types type0; role role52 types type0; role role53 types type0; role role54 types type0; role role55 types type0; role role56 types type0; role role57 types type0; role role58 types type0; role role59 types type0; role role60 types type0; role role61 types type0; role role62 types type0; role role63 types type0; role role64 types type0; role role65 types type0; role role66 types type0; role role67 types type0; role role68 types type0; role role69 types type0; role role70 types type0; role role71 types type0; role role72 types type0; role role73 types type0; role role74 types type0; role role75 types type0; role role76 types type0; role role77 types type0; role role78 types type0; role role79 types type0; role role80 types type0; role role81 types type0; role role82 types type0; role role83 types type0; role role84 types type0; role role85 types type0; role role86 types type0; role role87 types type0; role role88 types type0; role role89 types type0; role role90 types type0; role role91 types type0; role role92 types type0; role role93 types type0; role role94 types type0; role role95 types type0; role role96 types type0; role role97 types type0; role role98 types type0; role role99 types type0; role role100 types type0; role role101 types type0; role role102 types type0; role role103 types type0; role role104 types type0; role role105 types type0; role role106 types type0; role role107 types type0; role role108 types type0; role role109 types type0; role role110 types type0; role role111 types type0; role role112 types type0; role role113 types type0; role role114 types type0; role role115 types type0; role role116 types type0; role role117 types type0; role role118 types type0; role role119 types type0; role role120 types type0; role role121 types type0; role role122 types type0; role role123 types type0; role role124 types type0; role role125 types type0; role role126 types type0; role role127 types type0; role role128 types type0; role role129 types type0; # 137 types type type0 alias type_alias0; type type1 alias type_alias1; type type2 alias type_alias2; type type3; type type4; type type5; type type6; type type7; type type8; type type9; type type10; type type11; type type12; type type13; type type14; type type15; type type16; type type17; type type18; type type19; type type20; type type21; type type22; type type23; type type24; type type25; type type26; type type27; type type28; type type29; type type30; type type31; type type32; type type33; type type34; type type35; type type36; type type37; type type38; type type39; type type40; type type41; type type42; type type43; type type44; type type45; type type46; type type47; type type48; type type49; type type50; type type51; type type52; type type53; type type54; type type55; type type56; type type57; type type58; type type59; type type60; type type61; type type62; type type63; type type64; type type65; type type66; type type67; type type68; type type69; type type70; type type71; type type72; type type73; type type74; type type75; type type76; type type77; type type78; type type79; type type80; type type81; type type82; type type83; type type84; type type85; type type86; type type87; type type88; type type89; type type90; type type91; type type92; type type93; type type94; type type95; type type96; type type97; type type98; type type99; type type100; type type101; type type102; type type103; type type104; type type105; type type106; type type107; type type108; type type109; type type110; type type111; type type112; type type113; type type114; type type115; type type116; type type117; type type118; type type119; type type120; type type121; type type122; type type123; type type124; type type125; type type126; type type127; type type128; type type129; type type130; type type131; type type132; type type133; type type134; type type135; type type136; # 73 permissive types permissive type0; permissive type1; permissive type2; permissive type3; permissive type4; permissive type5; permissive type6; permissive type7; permissive type8; permissive type9; permissive type10; permissive type11; permissive type12; permissive type13; permissive type14; permissive type15; permissive type16; permissive type17; permissive type18; permissive type19; permissive type20; permissive type21; permissive type22; permissive type23; permissive type24; permissive type25; permissive type26; permissive type27; permissive type28; permissive type29; permissive type30; permissive type31; permissive type32; permissive type33; permissive type34; permissive type35; permissive type36; permissive type37; permissive type38; permissive type39; permissive type40; permissive type41; permissive type42; permissive type43; permissive type44; permissive type45; permissive type46; permissive type47; permissive type48; permissive type49; permissive type50; permissive type51; permissive type52; permissive type53; permissive type54; permissive type55; permissive type56; permissive type57; permissive type58; permissive type59; permissive type60; permissive type61; permissive type62; permissive type63; permissive type64; permissive type65; permissive type66; permissive type67; permissive type68; permissive type69; permissive type70; permissive type71; permissive type72; # 83 role allows allow role1 role0; allow role2 role1; allow role3 role2; allow role4 role3; allow role5 role4; allow role6 role5; allow role7 role6; allow role8 role7; allow role9 role8; allow role10 role9; allow role11 role10; allow role12 role11; allow role13 role12; allow role14 role13; allow role15 role14; allow role16 role15; allow role17 role16; allow role18 role17; allow role19 role18; allow role20 role19; allow role21 role20; allow role22 role21; allow role23 role22; allow role24 role23; allow role25 role24; allow role26 role25; allow role27 role26; allow role28 role27; allow role29 role28; allow role30 role29; allow role31 role30; allow role32 role31; allow role33 role32; allow role34 role33; allow role35 role34; allow role36 role35; allow role37 role36; allow role38 role37; allow role39 role38; allow role40 role39; allow role41 role40; allow role42 role41; allow role43 role42; allow role44 role43; allow role45 role44; allow role46 role45; allow role47 role46; allow role48 role47; allow role49 role48; allow role50 role49; allow role51 role50; allow role52 role51; allow role53 role52; allow role54 role53; allow role55 role54; allow role56 role55; allow role57 role56; allow role58 role57; allow role59 role58; allow role60 role59; allow role61 role60; allow role62 role61; allow role63 role62; allow role64 role63; allow role65 role64; allow role66 role65; allow role67 role66; allow role68 role67; allow role69 role68; allow role70 role69; allow role71 role70; allow role72 role71; allow role73 role72; allow role74 role73; allow role75 role74; allow role76 role75; allow role77 role76; allow role78 role77; allow role79 role78; allow role80 role79; allow role81 role80; allow role82 role81; allow role83 role82; # 79 role transitions role_transition role1 type0:infoflow role0; role_transition role2 type0:infoflow role1; role_transition role3 type0:infoflow role2; role_transition role4 type0:infoflow role3; role_transition role5 type0:infoflow role4; role_transition role6 type0:infoflow role5; role_transition role7 type0:infoflow role6; role_transition role8 type0:infoflow role7; role_transition role9 type0:infoflow role8; role_transition role10 type0:infoflow role9; role_transition role11 type0:infoflow role10; role_transition role12 type0:infoflow role11; role_transition role13 type0:infoflow role12; role_transition role14 type0:infoflow role13; role_transition role15 type0:infoflow role14; role_transition role16 type0:infoflow role15; role_transition role17 type0:infoflow role16; role_transition role18 type0:infoflow role17; role_transition role19 type0:infoflow role18; role_transition role20 type0:infoflow role19; role_transition role21 type0:infoflow role20; role_transition role22 type0:infoflow role21; role_transition role23 type0:infoflow role22; role_transition role24 type0:infoflow role23; role_transition role25 type0:infoflow role24; role_transition role26 type0:infoflow role25; role_transition role27 type0:infoflow role26; role_transition role28 type0:infoflow role27; role_transition role29 type0:infoflow role28; role_transition role30 type0:infoflow role29; role_transition role31 type0:infoflow role30; role_transition role32 type0:infoflow role31; role_transition role33 type0:infoflow role32; role_transition role34 type0:infoflow role33; role_transition role35 type0:infoflow role34; role_transition role36 type0:infoflow role35; role_transition role37 type0:infoflow role36; role_transition role38 type0:infoflow role37; role_transition role39 type0:infoflow role38; role_transition role40 type0:infoflow role39; role_transition role41 type0:infoflow role40; role_transition role42 type0:infoflow role41; role_transition role43 type0:infoflow role42; role_transition role44 type0:infoflow role43; role_transition role45 type0:infoflow role44; role_transition role46 type0:infoflow role45; role_transition role47 type0:infoflow role46; role_transition role48 type0:infoflow role47; role_transition role49 type0:infoflow role48; role_transition role50 type0:infoflow role49; role_transition role51 type0:infoflow role50; role_transition role52 type0:infoflow role51; role_transition role53 type0:infoflow role52; role_transition role54 type0:infoflow role53; role_transition role55 type0:infoflow role54; role_transition role56 type0:infoflow role55; role_transition role57 type0:infoflow role56; role_transition role58 type0:infoflow role57; role_transition role59 type0:infoflow role58; role_transition role60 type0:infoflow role59; role_transition role61 type0:infoflow role60; role_transition role62 type0:infoflow role61; role_transition role63 type0:infoflow role62; role_transition role64 type0:infoflow role63; role_transition role65 type0:infoflow role64; role_transition role66 type0:infoflow role65; role_transition role67 type0:infoflow role66; role_transition role68 type0:infoflow role67; role_transition role69 type0:infoflow role68; role_transition role70 type0:infoflow role69; role_transition role71 type0:infoflow role70; role_transition role72 type0:infoflow role71; role_transition role73 type0:infoflow role72; role_transition role74 type0:infoflow role73; role_transition role75 type0:infoflow role74; role_transition role76 type0:infoflow role75; role_transition role77 type0:infoflow role76; role_transition role78 type0:infoflow role77; role_transition role79 type0:infoflow role78; # 113 allow rules if ( bool0 ) { allow type0 type0:infoflow low_none; } if ( bool1 ) { allow type1 type1:infoflow low_none; } if ( bool2 ) { allow type2 type2:infoflow low_none; } if ( bool3 ) { allow type3 type3:infoflow low_none; } if ( bool4 ) { allow type4 type4:infoflow low_none; } if ( bool5 ) { allow type5 type5:infoflow low_none; } if ( bool6 ) { allow type6 type6:infoflow low_none; } if ( bool7 ) { allow type7 type7:infoflow low_none; } if ( bool8 ) { allow type8 type8:infoflow low_none; } if ( bool9 ) { allow type9 type9:infoflow low_none; } if ( bool10 ) { allow type10 type10:infoflow low_none; } if ( bool11 ) { allow type11 type11:infoflow low_none; } if ( bool12 ) { allow type12 type12:infoflow low_none; } if ( bool13 ) { allow type13 type13:infoflow low_none; } if ( bool14 ) { allow type14 type14:infoflow low_none; } if ( bool15 ) { allow type15 type15:infoflow low_none; } if ( bool16 ) { allow type16 type16:infoflow low_none; } if ( bool17 ) { allow type17 type17:infoflow low_none; } if ( bool18 ) { allow type18 type18:infoflow low_none; } if ( bool19 ) { allow type19 type19:infoflow low_none; } if ( bool20 ) { allow type20 type20:infoflow low_none; } if ( bool21 ) { allow type21 type21:infoflow low_none; } if ( bool22 ) { allow type22 type22:infoflow low_none; } if ( bool23 ) { allow type23 type23:infoflow low_none; } if ( bool24 ) { allow type24 type24:infoflow low_none; } if ( bool25 ) { allow type25 type25:infoflow low_none; } if ( bool26 ) { allow type26 type26:infoflow low_none; } if ( bool27 ) { allow type27 type27:infoflow low_none; } if ( bool28 ) { allow type28 type28:infoflow low_none; } if ( bool29 ) { allow type29 type29:infoflow low_none; } if ( bool30 ) { allow type30 type30:infoflow low_none; } if ( bool31 ) { allow type31 type31:infoflow low_none; } if ( bool32 ) { allow type32 type32:infoflow low_none; } if ( bool33 ) { allow type33 type33:infoflow low_none; } if ( bool34 ) { allow type34 type34:infoflow low_none; } if ( bool35 ) { allow type35 type35:infoflow low_none; } if ( bool36 ) { allow type36 type36:infoflow low_none; } if ( bool37 ) { allow type37 type37:infoflow low_none; } if ( bool38 ) { allow type38 type38:infoflow low_none; } if ( bool39 ) { allow type39 type39:infoflow low_none; } if ( bool40 ) { allow type40 type40:infoflow low_none; } if ( bool41 ) { allow type41 type41:infoflow low_none; } if ( bool42 ) { allow type42 type42:infoflow low_none; } if ( bool43 ) { allow type43 type43:infoflow low_none; } if ( bool44 ) { allow type44 type44:infoflow low_none; } if ( bool45 ) { allow type45 type45:infoflow low_none; } if ( bool46 ) { allow type46 type46:infoflow low_none; } if ( bool47 ) { allow type47 type47:infoflow low_none; } if ( bool48 ) { allow type48 type48:infoflow low_none; } if ( bool49 ) { allow type49 type49:infoflow low_none; } if ( bool50 ) { allow type50 type50:infoflow low_none; } if ( bool51 ) { allow type51 type51:infoflow low_none; } if ( bool52 ) { allow type52 type52:infoflow low_none; } if ( bool53 ) { allow type53 type53:infoflow low_none; } if ( bool54 ) { allow type54 type54:infoflow low_none; } if ( bool55 ) { allow type55 type55:infoflow low_none; } if ( bool56 ) { allow type56 type56:infoflow low_none; } if ( bool57 ) { allow type57 type57:infoflow low_none; } if ( bool58 ) { allow type58 type58:infoflow low_none; } if ( bool59 ) { allow type59 type59:infoflow low_none; } if ( bool60 ) { allow type60 type60:infoflow low_none; } if ( bool61 ) { allow type61 type61:infoflow low_none; } if ( bool62 ) { allow type62 type62:infoflow low_none; } if ( bool63 ) { allow type63 type63:infoflow low_none; } if ( bool64 ) { allow type64 type64:infoflow low_none; } if ( bool65 ) { allow type65 type65:infoflow low_none; } if ( bool66 ) { allow type66 type66:infoflow low_none; } allow type67 type67:infoflow low_none; allow type68 type68:infoflow low_none; allow type69 type69:infoflow low_none; allow type70 type70:infoflow low_none; allow type71 type71:infoflow low_none; allow type72 type72:infoflow low_none; allow type73 type73:infoflow low_none; allow type74 type74:infoflow low_none; allow type75 type75:infoflow low_none; allow type76 type76:infoflow low_none; allow type77 type77:infoflow low_none; allow type78 type78:infoflow low_none; allow type79 type79:infoflow low_none; allow type80 type80:infoflow low_none; allow type81 type81:infoflow low_none; allow type82 type82:infoflow low_none; allow type83 type83:infoflow low_none; allow type84 type84:infoflow low_none; allow type85 type85:infoflow low_none; allow type86 type86:infoflow low_none; allow type87 type87:infoflow low_none; allow type88 type88:infoflow low_none; allow type89 type89:infoflow low_none; allow type90 type90:infoflow low_none; allow type91 type91:infoflow low_none; allow type92 type92:infoflow low_none; allow type93 type93:infoflow low_none; allow type94 type94:infoflow low_none; allow type95 type95:infoflow low_none; allow type96 type96:infoflow low_none; allow type97 type97:infoflow low_none; allow type98 type98:infoflow low_none; allow type99 type99:infoflow low_none; allow type100 type100:infoflow low_none; allow type101 type101:infoflow low_none; allow type102 type102:infoflow low_none; allow type103 type103:infoflow low_none; allow type104 type104:infoflow low_none; allow type105 type105:infoflow low_none; allow type106 type106:infoflow low_none; allow type107 type107:infoflow low_none; allow type108 type108:infoflow low_none; allow type109 type109:infoflow low_none; allow type110 type110:infoflow low_none; allow type111 type111:infoflow low_none; allow type112 type112:infoflow low_none; # 109 auditallow rules auditallow type0 type0:infoflow low_w; auditallow type1 type1:infoflow low_w; auditallow type2 type2:infoflow low_w; auditallow type3 type3:infoflow low_w; auditallow type4 type4:infoflow low_w; auditallow type5 type5:infoflow low_w; auditallow type6 type6:infoflow low_w; auditallow type7 type7:infoflow low_w; auditallow type8 type8:infoflow low_w; auditallow type9 type9:infoflow low_w; auditallow type10 type10:infoflow low_w; auditallow type11 type11:infoflow low_w; auditallow type12 type12:infoflow low_w; auditallow type13 type13:infoflow low_w; auditallow type14 type14:infoflow low_w; auditallow type15 type15:infoflow low_w; auditallow type16 type16:infoflow low_w; auditallow type17 type17:infoflow low_w; auditallow type18 type18:infoflow low_w; auditallow type19 type19:infoflow low_w; auditallow type20 type20:infoflow low_w; auditallow type21 type21:infoflow low_w; auditallow type22 type22:infoflow low_w; auditallow type23 type23:infoflow low_w; auditallow type24 type24:infoflow low_w; auditallow type25 type25:infoflow low_w; auditallow type26 type26:infoflow low_w; auditallow type27 type27:infoflow low_w; auditallow type28 type28:infoflow low_w; auditallow type29 type29:infoflow low_w; auditallow type30 type30:infoflow low_w; auditallow type31 type31:infoflow low_w; auditallow type32 type32:infoflow low_w; auditallow type33 type33:infoflow low_w; auditallow type34 type34:infoflow low_w; auditallow type35 type35:infoflow low_w; auditallow type36 type36:infoflow low_w; auditallow type37 type37:infoflow low_w; auditallow type38 type38:infoflow low_w; auditallow type39 type39:infoflow low_w; auditallow type40 type40:infoflow low_w; auditallow type41 type41:infoflow low_w; auditallow type42 type42:infoflow low_w; auditallow type43 type43:infoflow low_w; auditallow type44 type44:infoflow low_w; auditallow type45 type45:infoflow low_w; auditallow type46 type46:infoflow low_w; auditallow type47 type47:infoflow low_w; auditallow type48 type48:infoflow low_w; auditallow type49 type49:infoflow low_w; auditallow type50 type50:infoflow low_w; auditallow type51 type51:infoflow low_w; auditallow type52 type52:infoflow low_w; auditallow type53 type53:infoflow low_w; auditallow type54 type54:infoflow low_w; auditallow type55 type55:infoflow low_w; auditallow type56 type56:infoflow low_w; auditallow type57 type57:infoflow low_w; auditallow type58 type58:infoflow low_w; auditallow type59 type59:infoflow low_w; auditallow type60 type60:infoflow low_w; auditallow type61 type61:infoflow low_w; auditallow type62 type62:infoflow low_w; auditallow type63 type63:infoflow low_w; auditallow type64 type64:infoflow low_w; auditallow type65 type65:infoflow low_w; auditallow type66 type66:infoflow low_w; auditallow type67 type67:infoflow low_w; auditallow type68 type68:infoflow low_w; auditallow type69 type69:infoflow low_w; auditallow type70 type70:infoflow low_w; auditallow type71 type71:infoflow low_w; auditallow type72 type72:infoflow low_w; auditallow type73 type73:infoflow low_w; auditallow type74 type74:infoflow low_w; auditallow type75 type75:infoflow low_w; auditallow type76 type76:infoflow low_w; auditallow type77 type77:infoflow low_w; auditallow type78 type78:infoflow low_w; auditallow type79 type79:infoflow low_w; auditallow type80 type80:infoflow low_w; auditallow type81 type81:infoflow low_w; auditallow type82 type82:infoflow low_w; auditallow type83 type83:infoflow low_w; auditallow type84 type84:infoflow low_w; auditallow type85 type85:infoflow low_w; auditallow type86 type86:infoflow low_w; auditallow type87 type87:infoflow low_w; auditallow type88 type88:infoflow low_w; auditallow type89 type89:infoflow low_w; auditallow type90 type90:infoflow low_w; auditallow type91 type91:infoflow low_w; auditallow type92 type92:infoflow low_w; auditallow type93 type93:infoflow low_w; auditallow type94 type94:infoflow low_w; auditallow type95 type95:infoflow low_w; auditallow type96 type96:infoflow low_w; auditallow type97 type97:infoflow low_w; auditallow type98 type98:infoflow low_w; auditallow type99 type99:infoflow low_w; auditallow type100 type100:infoflow low_w; auditallow type101 type101:infoflow low_w; auditallow type102 type102:infoflow low_w; auditallow type103 type103:infoflow low_w; auditallow type104 type104:infoflow low_w; auditallow type105 type105:infoflow low_w; auditallow type106 type106:infoflow low_w; auditallow type107 type107:infoflow low_w; auditallow type108 type108:infoflow low_w; # 107 dontaudit rules dontaudit type0 type0:infoflow low_r; dontaudit type1 type1:infoflow low_r; dontaudit type2 type2:infoflow low_r; dontaudit type3 type3:infoflow low_r; dontaudit type4 type4:infoflow low_r; dontaudit type5 type5:infoflow low_r; dontaudit type6 type6:infoflow low_r; dontaudit type7 type7:infoflow low_r; dontaudit type8 type8:infoflow low_r; dontaudit type9 type9:infoflow low_r; dontaudit type10 type10:infoflow low_r; dontaudit type11 type11:infoflow low_r; dontaudit type12 type12:infoflow low_r; dontaudit type13 type13:infoflow low_r; dontaudit type14 type14:infoflow low_r; dontaudit type15 type15:infoflow low_r; dontaudit type16 type16:infoflow low_r; dontaudit type17 type17:infoflow low_r; dontaudit type18 type18:infoflow low_r; dontaudit type19 type19:infoflow low_r; dontaudit type20 type20:infoflow low_r; dontaudit type21 type21:infoflow low_r; dontaudit type22 type22:infoflow low_r; dontaudit type23 type23:infoflow low_r; dontaudit type24 type24:infoflow low_r; dontaudit type25 type25:infoflow low_r; dontaudit type26 type26:infoflow low_r; dontaudit type27 type27:infoflow low_r; dontaudit type28 type28:infoflow low_r; dontaudit type29 type29:infoflow low_r; dontaudit type30 type30:infoflow low_r; dontaudit type31 type31:infoflow low_r; dontaudit type32 type32:infoflow low_r; dontaudit type33 type33:infoflow low_r; dontaudit type34 type34:infoflow low_r; dontaudit type35 type35:infoflow low_r; dontaudit type36 type36:infoflow low_r; dontaudit type37 type37:infoflow low_r; dontaudit type38 type38:infoflow low_r; dontaudit type39 type39:infoflow low_r; dontaudit type40 type40:infoflow low_r; dontaudit type41 type41:infoflow low_r; dontaudit type42 type42:infoflow low_r; dontaudit type43 type43:infoflow low_r; dontaudit type44 type44:infoflow low_r; dontaudit type45 type45:infoflow low_r; dontaudit type46 type46:infoflow low_r; dontaudit type47 type47:infoflow low_r; dontaudit type48 type48:infoflow low_r; dontaudit type49 type49:infoflow low_r; dontaudit type50 type50:infoflow low_r; dontaudit type51 type51:infoflow low_r; dontaudit type52 type52:infoflow low_r; dontaudit type53 type53:infoflow low_r; dontaudit type54 type54:infoflow low_r; dontaudit type55 type55:infoflow low_r; dontaudit type56 type56:infoflow low_r; dontaudit type57 type57:infoflow low_r; dontaudit type58 type58:infoflow low_r; dontaudit type59 type59:infoflow low_r; dontaudit type60 type60:infoflow low_r; dontaudit type61 type61:infoflow low_r; dontaudit type62 type62:infoflow low_r; dontaudit type63 type63:infoflow low_r; dontaudit type64 type64:infoflow low_r; dontaudit type65 type65:infoflow low_r; dontaudit type66 type66:infoflow low_r; dontaudit type67 type67:infoflow low_r; dontaudit type68 type68:infoflow low_r; dontaudit type69 type69:infoflow low_r; dontaudit type70 type70:infoflow low_r; dontaudit type71 type71:infoflow low_r; dontaudit type72 type72:infoflow low_r; dontaudit type73 type73:infoflow low_r; dontaudit type74 type74:infoflow low_r; dontaudit type75 type75:infoflow low_r; dontaudit type76 type76:infoflow low_r; dontaudit type77 type77:infoflow low_r; dontaudit type78 type78:infoflow low_r; dontaudit type79 type79:infoflow low_r; dontaudit type80 type80:infoflow low_r; dontaudit type81 type81:infoflow low_r; dontaudit type82 type82:infoflow low_r; dontaudit type83 type83:infoflow low_r; dontaudit type84 type84:infoflow low_r; dontaudit type85 type85:infoflow low_r; dontaudit type86 type86:infoflow low_r; dontaudit type87 type87:infoflow low_r; dontaudit type88 type88:infoflow low_r; dontaudit type89 type89:infoflow low_r; dontaudit type90 type90:infoflow low_r; dontaudit type91 type91:infoflow low_r; dontaudit type92 type92:infoflow low_r; dontaudit type93 type93:infoflow low_r; dontaudit type94 type94:infoflow low_r; dontaudit type95 type95:infoflow low_r; dontaudit type96 type96:infoflow low_r; dontaudit type97 type97:infoflow low_r; dontaudit type98 type98:infoflow low_r; dontaudit type99 type99:infoflow low_r; dontaudit type100 type100:infoflow low_r; dontaudit type101 type101:infoflow low_r; dontaudit type102 type102:infoflow low_r; dontaudit type103 type103:infoflow low_r; dontaudit type104 type104:infoflow low_r; dontaudit type105 type105:infoflow low_r; dontaudit type106 type106:infoflow low_r; # 103 neverallow neverallow type0 type0:infoflow2 super_w; neverallow type1 type1:infoflow2 super_w; neverallow type2 type2:infoflow2 super_w; neverallow type3 type3:infoflow2 super_w; neverallow type4 type4:infoflow2 super_w; neverallow type5 type5:infoflow2 super_w; neverallow type6 type6:infoflow2 super_w; neverallow type7 type7:infoflow2 super_w; neverallow type8 type8:infoflow2 super_w; neverallow type9 type9:infoflow2 super_w; neverallow type10 type10:infoflow2 super_w; neverallow type11 type11:infoflow2 super_w; neverallow type12 type12:infoflow2 super_w; neverallow type13 type13:infoflow2 super_w; neverallow type14 type14:infoflow2 super_w; neverallow type15 type15:infoflow2 super_w; neverallow type16 type16:infoflow2 super_w; neverallow type17 type17:infoflow2 super_w; neverallow type18 type18:infoflow2 super_w; neverallow type19 type19:infoflow2 super_w; neverallow type20 type20:infoflow2 super_w; neverallow type21 type21:infoflow2 super_w; neverallow type22 type22:infoflow2 super_w; neverallow type23 type23:infoflow2 super_w; neverallow type24 type24:infoflow2 super_w; neverallow type25 type25:infoflow2 super_w; neverallow type26 type26:infoflow2 super_w; neverallow type27 type27:infoflow2 super_w; neverallow type28 type28:infoflow2 super_w; neverallow type29 type29:infoflow2 super_w; neverallow type30 type30:infoflow2 super_w; neverallow type31 type31:infoflow2 super_w; neverallow type32 type32:infoflow2 super_w; neverallow type33 type33:infoflow2 super_w; neverallow type34 type34:infoflow2 super_w; neverallow type35 type35:infoflow2 super_w; neverallow type36 type36:infoflow2 super_w; neverallow type37 type37:infoflow2 super_w; neverallow type38 type38:infoflow2 super_w; neverallow type39 type39:infoflow2 super_w; neverallow type40 type40:infoflow2 super_w; neverallow type41 type41:infoflow2 super_w; neverallow type42 type42:infoflow2 super_w; neverallow type43 type43:infoflow2 super_w; neverallow type44 type44:infoflow2 super_w; neverallow type45 type45:infoflow2 super_w; neverallow type46 type46:infoflow2 super_w; neverallow type47 type47:infoflow2 super_w; neverallow type48 type48:infoflow2 super_w; neverallow type49 type49:infoflow2 super_w; neverallow type50 type50:infoflow2 super_w; neverallow type51 type51:infoflow2 super_w; neverallow type52 type52:infoflow2 super_w; neverallow type53 type53:infoflow2 super_w; neverallow type54 type54:infoflow2 super_w; neverallow type55 type55:infoflow2 super_w; neverallow type56 type56:infoflow2 super_w; neverallow type57 type57:infoflow2 super_w; neverallow type58 type58:infoflow2 super_w; neverallow type59 type59:infoflow2 super_w; neverallow type60 type60:infoflow2 super_w; neverallow type61 type61:infoflow2 super_w; neverallow type62 type62:infoflow2 super_w; neverallow type63 type63:infoflow2 super_w; neverallow type64 type64:infoflow2 super_w; neverallow type65 type65:infoflow2 super_w; neverallow type66 type66:infoflow2 super_w; neverallow type67 type67:infoflow2 super_w; neverallow type68 type68:infoflow2 super_w; neverallow type69 type69:infoflow2 super_w; neverallow type70 type70:infoflow2 super_w; neverallow type71 type71:infoflow2 super_w; neverallow type72 type72:infoflow2 super_w; neverallow type73 type73:infoflow2 super_w; neverallow type74 type74:infoflow2 super_w; neverallow type75 type75:infoflow2 super_w; neverallow type76 type76:infoflow2 super_w; neverallow type77 type77:infoflow2 super_w; neverallow type78 type78:infoflow2 super_w; neverallow type79 type79:infoflow2 super_w; neverallow type80 type80:infoflow2 super_w; neverallow type81 type81:infoflow2 super_w; neverallow type82 type82:infoflow2 super_w; neverallow type83 type83:infoflow2 super_w; neverallow type84 type84:infoflow2 super_w; neverallow type85 type85:infoflow2 super_w; neverallow type86 type86:infoflow2 super_w; neverallow type87 type87:infoflow2 super_w; neverallow type88 type88:infoflow2 super_w; neverallow type89 type89:infoflow2 super_w; neverallow type90 type90:infoflow2 super_w; neverallow type91 type91:infoflow2 super_w; neverallow type92 type92:infoflow2 super_w; neverallow type93 type93:infoflow2 super_w; neverallow type94 type94:infoflow2 super_w; neverallow type95 type95:infoflow2 super_w; neverallow type96 type96:infoflow2 super_w; neverallow type97 type97:infoflow2 super_w; neverallow type98 type98:infoflow2 super_w; neverallow type99 type99:infoflow2 super_w; neverallow type100 type100:infoflow2 super_w; neverallow type101 type101:infoflow2 super_w; neverallow type102 type102:infoflow2 super_w; # 97 type_transition rules type_transition type1 type0:infoflow type1; type_transition type2 type1:infoflow type2; type_transition type3 type2:infoflow type3; type_transition type4 type3:infoflow type4; type_transition type5 type4:infoflow type5; type_transition type6 type5:infoflow type6; type_transition type7 type6:infoflow type7; type_transition type8 type7:infoflow type8; type_transition type9 type8:infoflow type9; type_transition type10 type9:infoflow type10; type_transition type11 type10:infoflow type11; type_transition type12 type11:infoflow type12; type_transition type13 type12:infoflow type13; type_transition type14 type13:infoflow type14; type_transition type15 type14:infoflow type15; type_transition type16 type15:infoflow type16; type_transition type17 type16:infoflow type17; type_transition type18 type17:infoflow type18; type_transition type19 type18:infoflow type19; type_transition type20 type19:infoflow type20; type_transition type21 type20:infoflow type21; type_transition type22 type21:infoflow type22; type_transition type23 type22:infoflow type23; type_transition type24 type23:infoflow type24; type_transition type25 type24:infoflow type25; type_transition type26 type25:infoflow type26; type_transition type27 type26:infoflow type27; type_transition type28 type27:infoflow type28; type_transition type29 type28:infoflow type29; type_transition type30 type29:infoflow type30; type_transition type31 type30:infoflow type31; type_transition type32 type31:infoflow type32; type_transition type33 type32:infoflow type33; type_transition type34 type33:infoflow type34; type_transition type35 type34:infoflow type35; type_transition type36 type35:infoflow type36; type_transition type37 type36:infoflow type37; type_transition type38 type37:infoflow type38; type_transition type39 type38:infoflow type39; type_transition type40 type39:infoflow type40; type_transition type41 type40:infoflow type41; type_transition type42 type41:infoflow type42; type_transition type43 type42:infoflow type43; type_transition type44 type43:infoflow type44; type_transition type45 type44:infoflow type45; type_transition type46 type45:infoflow type46; type_transition type47 type46:infoflow type47; type_transition type48 type47:infoflow type48; type_transition type49 type48:infoflow type49; type_transition type50 type49:infoflow type50 "name50"; type_transition type51 type50:infoflow type51 "name51"; type_transition type52 type51:infoflow type52 "name52"; type_transition type53 type52:infoflow type53 "name53"; type_transition type54 type53:infoflow type54 "name54"; type_transition type55 type54:infoflow type55 "name55"; type_transition type56 type55:infoflow type56 "name56"; type_transition type57 type56:infoflow type57 "name57"; type_transition type58 type57:infoflow type58 "name58"; type_transition type59 type58:infoflow type59 "name59"; type_transition type60 type59:infoflow type60 "name60"; type_transition type61 type60:infoflow type61 "name61"; type_transition type62 type61:infoflow type62 "name62"; type_transition type63 type62:infoflow type63 "name63"; type_transition type64 type63:infoflow type64 "name64"; type_transition type65 type64:infoflow type65 "name65"; type_transition type66 type65:infoflow type66 "name66"; type_transition type67 type66:infoflow type67 "name67"; type_transition type68 type67:infoflow type68 "name68"; type_transition type69 type68:infoflow type69 "name69"; type_transition type70 type69:infoflow type70 "name70"; type_transition type71 type70:infoflow type71 "name71"; type_transition type72 type71:infoflow type72 "name72"; type_transition type73 type72:infoflow type73 "name73"; type_transition type74 type73:infoflow type74 "name74"; type_transition type75 type74:infoflow type75 "name75"; type_transition type76 type75:infoflow type76 "name76"; type_transition type77 type76:infoflow type77 "name77"; type_transition type78 type77:infoflow type78 "name78"; type_transition type79 type78:infoflow type79 "name79"; type_transition type80 type79:infoflow type80 "name80"; type_transition type81 type80:infoflow type81 "name81"; type_transition type82 type81:infoflow type82 "name82"; type_transition type83 type82:infoflow type83 "name83"; type_transition type84 type83:infoflow type84 "name84"; type_transition type85 type84:infoflow type85 "name85"; type_transition type86 type85:infoflow type86 "name86"; type_transition type87 type86:infoflow type87 "name87"; type_transition type88 type87:infoflow type88 "name88"; type_transition type89 type88:infoflow type89 "name89"; type_transition type90 type89:infoflow type90 "name90"; type_transition type91 type90:infoflow type91 "name91"; type_transition type92 type91:infoflow type92 "name92"; type_transition type93 type92:infoflow type93 "name93"; type_transition type94 type93:infoflow type94 "name94"; type_transition type2 type93:infoflow type4 "name94"; type_transition type3 type93:infoflow type4 "name94"; type_transition type4 type93:infoflow type94 "name94"; # 89 type_change type_change type1 type0:infoflow type1; type_change type2 type1:infoflow type2; type_change type3 type2:infoflow type3; type_change type4 type3:infoflow type4; type_change type5 type4:infoflow type5; type_change type6 type5:infoflow type6; type_change type7 type6:infoflow type7; type_change type8 type7:infoflow type8; type_change type9 type8:infoflow type9; type_change type10 type9:infoflow type10; type_change type11 type10:infoflow type11; type_change type12 type11:infoflow type12; type_change type13 type12:infoflow type13; type_change type14 type13:infoflow type14; type_change type15 type14:infoflow type15; type_change type16 type15:infoflow type16; type_change type17 type16:infoflow type17; type_change type18 type17:infoflow type18; type_change type19 type18:infoflow type19; type_change type20 type19:infoflow type20; type_change type21 type20:infoflow type21; type_change type22 type21:infoflow type22; type_change type23 type22:infoflow type23; type_change type24 type23:infoflow type24; type_change type25 type24:infoflow type25; type_change type26 type25:infoflow type26; type_change type27 type26:infoflow type27; type_change type28 type27:infoflow type28; type_change type29 type28:infoflow type29; type_change type30 type29:infoflow type30; type_change type31 type30:infoflow type31; type_change type32 type31:infoflow type32; type_change type33 type32:infoflow type33; type_change type34 type33:infoflow type34; type_change type35 type34:infoflow type35; type_change type36 type35:infoflow type36; type_change type37 type36:infoflow type37; type_change type38 type37:infoflow type38; type_change type39 type38:infoflow type39; type_change type40 type39:infoflow type40; type_change type41 type40:infoflow type41; type_change type42 type41:infoflow type42; type_change type43 type42:infoflow type43; type_change type44 type43:infoflow type44; type_change type45 type44:infoflow type45; type_change type46 type45:infoflow type46; type_change type47 type46:infoflow type47; type_change type48 type47:infoflow type48; type_change type49 type48:infoflow type49; type_change type50 type49:infoflow type50; type_change type51 type50:infoflow type51; type_change type52 type51:infoflow type52; type_change type53 type52:infoflow type53; type_change type54 type53:infoflow type54; type_change type55 type54:infoflow type55; type_change type56 type55:infoflow type56; type_change type57 type56:infoflow type57; type_change type58 type57:infoflow type58; type_change type59 type58:infoflow type59; type_change type60 type59:infoflow type60; type_change type61 type60:infoflow type61; type_change type62 type61:infoflow type62; type_change type63 type62:infoflow type63; type_change type64 type63:infoflow type64; type_change type65 type64:infoflow type65; type_change type66 type65:infoflow type66; type_change type67 type66:infoflow type67; type_change type68 type67:infoflow type68; type_change type69 type68:infoflow type69; type_change type70 type69:infoflow type70; type_change type71 type70:infoflow type71; type_change type72 type71:infoflow type72; type_change type73 type72:infoflow type73; type_change type74 type73:infoflow type74; type_change type75 type74:infoflow type75; type_change type76 type75:infoflow type76; type_change type77 type76:infoflow type77; type_change type78 type77:infoflow type78; type_change type79 type78:infoflow type79; type_change type80 type79:infoflow type80; type_change type81 type80:infoflow type81; type_change type82 type81:infoflow type82; type_change type83 type82:infoflow type83; type_change type84 type83:infoflow type84; type_change type85 type84:infoflow type85; type_change type86 type85:infoflow type86; type_change type87 type86:infoflow type87; type_change type88 type87:infoflow type88; type_change type89 type88:infoflow type89; # 61 type_member type_member type1 type0:infoflow type1; type_member type2 type1:infoflow type2; type_member type3 type2:infoflow type3; type_member type4 type3:infoflow type4; type_member type5 type4:infoflow type5; type_member type6 type5:infoflow type6; type_member type7 type6:infoflow type7; type_member type8 type7:infoflow type8; type_member type9 type8:infoflow type9; type_member type10 type9:infoflow type10; type_member type11 type10:infoflow type11; type_member type12 type11:infoflow type12; type_member type13 type12:infoflow type13; type_member type14 type13:infoflow type14; type_member type15 type14:infoflow type15; type_member type16 type15:infoflow type16; type_member type17 type16:infoflow type17; type_member type18 type17:infoflow type18; type_member type19 type18:infoflow type19; type_member type20 type19:infoflow type20; type_member type21 type20:infoflow type21; type_member type22 type21:infoflow type22; type_member type23 type22:infoflow type23; type_member type24 type23:infoflow type24; type_member type25 type24:infoflow type25; type_member type26 type25:infoflow type26; type_member type27 type26:infoflow type27; type_member type28 type27:infoflow type28; type_member type29 type28:infoflow type29; type_member type30 type29:infoflow type30; type_member type31 type30:infoflow type31; type_member type32 type31:infoflow type32; type_member type33 type32:infoflow type33; type_member type34 type33:infoflow type34; type_member type35 type34:infoflow type35; type_member type36 type35:infoflow type36; type_member type37 type36:infoflow type37; type_member type38 type37:infoflow type38; type_member type39 type38:infoflow type39; type_member type40 type39:infoflow type40; type_member type41 type40:infoflow type41; type_member type42 type41:infoflow type42; type_member type43 type42:infoflow type43; type_member type44 type43:infoflow type44; type_member type45 type44:infoflow type45; type_member type46 type45:infoflow type46; type_member type47 type46:infoflow type47; type_member type48 type47:infoflow type48; type_member type49 type48:infoflow type49; type_member type50 type49:infoflow type50; type_member type51 type50:infoflow type51; type_member type52 type51:infoflow type52; type_member type53 type52:infoflow type53; type_member type54 type53:infoflow type54; type_member type55 type54:infoflow type55; type_member type56 type55:infoflow type56; type_member type57 type56:infoflow type57; type_member type58 type57:infoflow type58; type_member type59 type58:infoflow type59; type_member type60 type59:infoflow type60; type_member type61 type60:infoflow type61; # 71 range transitions range_transition type0 type0:infoflow s3; range_transition type1 type1:infoflow s3; range_transition type2 type2:infoflow s3; range_transition type3 type3:infoflow s3; range_transition type4 type4:infoflow s3; range_transition type5 type5:infoflow s3; range_transition type6 type6:infoflow s3; range_transition type7 type7:infoflow s3; range_transition type8 type8:infoflow s3; range_transition type9 type9:infoflow s3; range_transition type10 type10:infoflow s3; range_transition type11 type11:infoflow s3; range_transition type12 type12:infoflow s3; range_transition type13 type13:infoflow s3; range_transition type14 type14:infoflow s3; range_transition type15 type15:infoflow s3; range_transition type16 type16:infoflow s3; range_transition type17 type17:infoflow s3; range_transition type18 type18:infoflow s3; range_transition type19 type19:infoflow s3; range_transition type20 type20:infoflow s3; range_transition type21 type21:infoflow s3; range_transition type22 type22:infoflow s3; range_transition type23 type23:infoflow s3; range_transition type24 type24:infoflow s3; range_transition type25 type25:infoflow s3; range_transition type26 type26:infoflow s3; range_transition type27 type27:infoflow s3; range_transition type28 type28:infoflow s3; range_transition type29 type29:infoflow s3; range_transition type30 type30:infoflow s3; range_transition type31 type31:infoflow s3; range_transition type32 type32:infoflow s3; range_transition type33 type33:infoflow s3; range_transition type34 type34:infoflow s3; range_transition type35 type35:infoflow s3; range_transition type36 type36:infoflow s3; range_transition type37 type37:infoflow s3; range_transition type38 type38:infoflow s3; range_transition type39 type39:infoflow s3; range_transition type40 type40:infoflow s3; range_transition type41 type41:infoflow s3; range_transition type42 type42:infoflow s3; range_transition type43 type43:infoflow s3; range_transition type44 type44:infoflow s3; range_transition type45 type45:infoflow s3; range_transition type46 type46:infoflow s3; range_transition type47 type47:infoflow s3; range_transition type48 type48:infoflow s3; range_transition type49 type49:infoflow s3; range_transition type50 type50:infoflow s3; range_transition type51 type51:infoflow s3; range_transition type52 type52:infoflow s3; range_transition type53 type53:infoflow s3; range_transition type54 type54:infoflow s3; range_transition type55 type55:infoflow s3; range_transition type56 type56:infoflow s3; range_transition type57 type57:infoflow s3; range_transition type58 type58:infoflow s3; range_transition type59 type59:infoflow s3; range_transition type60 type60:infoflow s3; range_transition type61 type61:infoflow s3; range_transition type62 type62:infoflow s3; range_transition type63 type63:infoflow s3; range_transition type64 type64:infoflow s3; range_transition type65 type65:infoflow s3; range_transition type66 type66:infoflow s3; range_transition type67 type67:infoflow s3; range_transition type68 type68:infoflow s3; range_transition type69 type69:infoflow s3; range_transition type70 type70:infoflow s3; # 179 allowxperm rules allowxperm type0 type1:infoflow6 ioctl 0x1234; allowxperm type1 type2:infoflow6 ioctl 0x1234; allowxperm type2 type3:infoflow6 ioctl 0x1234; allowxperm type3 type4:infoflow6 ioctl 0x1234; allowxperm type4 type5:infoflow6 ioctl 0x1234; allowxperm type5 type6:infoflow6 ioctl 0x1234; allowxperm type6 type7:infoflow6 ioctl 0x1234; allowxperm type7 type8:infoflow6 ioctl 0x1234; allowxperm type8 type9:infoflow6 ioctl 0x1234; allowxperm type9 type10:infoflow6 ioctl 0x1234; allowxperm type10 type11:infoflow6 ioctl 0x1234; allowxperm type11 type12:infoflow6 ioctl 0x1234; allowxperm type12 type13:infoflow6 ioctl 0x1234; allowxperm type13 type14:infoflow6 ioctl 0x1234; allowxperm type14 type15:infoflow6 ioctl 0x1234; allowxperm type15 type16:infoflow6 ioctl 0x1234; allowxperm type16 type17:infoflow6 ioctl 0x1234; allowxperm type17 type18:infoflow6 ioctl 0x1234; allowxperm type18 type19:infoflow6 ioctl 0x1234; allowxperm type19 type20:infoflow6 ioctl 0x1234; allowxperm type20 type21:infoflow6 ioctl 0x1234; allowxperm type21 type22:infoflow6 ioctl 0x1234; allowxperm type22 type23:infoflow6 ioctl 0x1234; allowxperm type23 type24:infoflow6 ioctl 0x1234; allowxperm type24 type25:infoflow6 ioctl 0x1234; allowxperm type25 type26:infoflow6 ioctl 0x1234; allowxperm type26 type27:infoflow6 ioctl 0x1234; allowxperm type27 type28:infoflow6 ioctl 0x1234; allowxperm type28 type29:infoflow6 ioctl 0x1234; allowxperm type29 type30:infoflow6 ioctl 0x1234; allowxperm type30 type31:infoflow6 ioctl 0x1234; allowxperm type31 type32:infoflow6 ioctl 0x1234; allowxperm type32 type33:infoflow6 ioctl 0x1234; allowxperm type33 type34:infoflow6 ioctl 0x1234; allowxperm type34 type35:infoflow6 ioctl 0x1234; allowxperm type35 type36:infoflow6 ioctl 0x1234; allowxperm type36 type37:infoflow6 ioctl 0x1234; allowxperm type37 type38:infoflow6 ioctl 0x1234; allowxperm type38 type39:infoflow6 ioctl 0x1234; allowxperm type39 type40:infoflow6 ioctl 0x1234; allowxperm type40 type41:infoflow6 ioctl 0x1234; allowxperm type41 type42:infoflow6 ioctl 0x1234; allowxperm type42 type43:infoflow6 ioctl 0x1234; allowxperm type43 type44:infoflow6 ioctl 0x1234; allowxperm type44 type45:infoflow6 ioctl 0x1234; allowxperm type45 type46:infoflow6 ioctl 0x1234; allowxperm type46 type47:infoflow6 ioctl 0x1234; allowxperm type47 type48:infoflow6 ioctl 0x1234; allowxperm type48 type49:infoflow6 ioctl 0x1234; allowxperm type49 type50:infoflow6 ioctl 0x1234; allowxperm type50 type51:infoflow6 ioctl 0x1234; allowxperm type51 type52:infoflow6 ioctl 0x1234; allowxperm type52 type53:infoflow6 ioctl 0x1234; allowxperm type53 type54:infoflow6 ioctl 0x1234; allowxperm type54 type55:infoflow6 ioctl 0x1234; allowxperm type55 type56:infoflow6 ioctl 0x1234; allowxperm type56 type57:infoflow6 ioctl 0x1234; allowxperm type57 type58:infoflow6 ioctl 0x1234; allowxperm type58 type59:infoflow6 ioctl 0x1234; allowxperm type59 type60:infoflow6 ioctl 0x1234; allowxperm type60 type61:infoflow6 ioctl 0x1234; allowxperm type61 type62:infoflow6 ioctl 0x1234; allowxperm type62 type63:infoflow6 ioctl 0x1234; allowxperm type63 type64:infoflow6 ioctl 0x1234; allowxperm type64 type65:infoflow6 ioctl 0x1234; allowxperm type65 type66:infoflow6 ioctl 0x1234; allowxperm type66 type67:infoflow6 ioctl 0x1234; allowxperm type67 type68:infoflow6 ioctl 0x1234; allowxperm type68 type69:infoflow6 ioctl 0x1234; allowxperm type69 type70:infoflow6 ioctl 0x1234; allowxperm type70 type71:infoflow6 ioctl 0x1234; allowxperm type71 type72:infoflow6 ioctl 0x1234; allowxperm type72 type73:infoflow6 ioctl 0x1234; allowxperm type73 type74:infoflow6 ioctl 0x1234; allowxperm type74 type75:infoflow6 ioctl 0x1234; allowxperm type75 type76:infoflow6 ioctl 0x1234; allowxperm type76 type77:infoflow6 ioctl 0x1234; allowxperm type77 type78:infoflow6 ioctl 0x1234; allowxperm type78 type79:infoflow6 ioctl 0x1234; allowxperm type79 type80:infoflow6 ioctl 0x1234; allowxperm type80 type81:infoflow6 ioctl 0x1234; allowxperm type81 type82:infoflow6 ioctl 0x1234; allowxperm type82 type83:infoflow6 ioctl 0x1234; allowxperm type83 type84:infoflow6 ioctl 0x1234; allowxperm type84 type85:infoflow6 ioctl 0x1234; allowxperm type85 type86:infoflow6 ioctl 0x1234; allowxperm type86 type87:infoflow6 ioctl 0x1234; allowxperm type87 type88:infoflow6 ioctl 0x1234; allowxperm type88 type89:infoflow6 ioctl 0x1234; allowxperm type89 type90:infoflow6 ioctl 0x1234; allowxperm type90 type91:infoflow6 ioctl 0x1234; allowxperm type91 type92:infoflow6 ioctl 0x1234; allowxperm type92 type93:infoflow6 ioctl 0x1234; allowxperm type93 type94:infoflow6 ioctl 0x1234; allowxperm type94 type95:infoflow6 ioctl 0x1234; allowxperm type95 type96:infoflow6 ioctl 0x1234; allowxperm type96 type97:infoflow6 ioctl 0x1234; allowxperm type97 type98:infoflow6 ioctl 0x1234; allowxperm type98 type99:infoflow6 ioctl 0x1234; allowxperm type99 type100:infoflow6 ioctl 0x1234; allowxperm type100 type101:infoflow6 ioctl 0x1234; allowxperm type101 type102:infoflow6 ioctl 0x1234; allowxperm type102 type103:infoflow6 ioctl 0x1234; allowxperm type103 type104:infoflow6 ioctl 0x1234; allowxperm type104 type105:infoflow6 ioctl 0x1234; allowxperm type105 type106:infoflow6 ioctl 0x1234; allowxperm type106 type107:infoflow6 ioctl 0x1234; allowxperm type107 type108:infoflow6 ioctl 0x1234; allowxperm type108 type109:infoflow6 ioctl 0x1234; allowxperm type109 type110:infoflow6 ioctl 0x1234; allowxperm type110 type111:infoflow6 ioctl 0x1234; allowxperm type111 type112:infoflow6 ioctl 0x1234; allowxperm type112 type113:infoflow6 ioctl 0x1234; allowxperm type113 type114:infoflow6 ioctl 0x1234; allowxperm type114 type115:infoflow6 ioctl 0x1234; allowxperm type115 type116:infoflow6 ioctl 0x1234; allowxperm type116 type117:infoflow6 ioctl 0x1234; allowxperm type117 type118:infoflow6 ioctl 0x1234; allowxperm type118 type119:infoflow6 ioctl 0x1234; allowxperm type119 type120:infoflow6 ioctl 0x1234; allowxperm type120 type121:infoflow6 ioctl 0x1234; allowxperm type121 type122:infoflow6 ioctl 0x1234; allowxperm type122 type123:infoflow6 ioctl 0x1234; allowxperm type123 type124:infoflow6 ioctl 0x1234; allowxperm type124 type125:infoflow6 ioctl 0x1234; allowxperm type125 type126:infoflow6 ioctl 0x1234; allowxperm type126 type127:infoflow6 ioctl 0x1234; allowxperm type127 type128:infoflow6 ioctl 0x1234; allowxperm type128 type129:infoflow6 ioctl 0x1234; allowxperm type129 type130:infoflow6 ioctl 0x1234; allowxperm type130 type131:infoflow6 ioctl 0x1234; allowxperm type131 type132:infoflow6 ioctl 0x1234; allowxperm type132 type133:infoflow6 ioctl 0x1234; allowxperm type133 type134:infoflow6 ioctl 0x1234; allowxperm type134 type135:infoflow6 ioctl 0x1234; allowxperm type135 type136:infoflow6 ioctl 0x1234; allowxperm type136 type0:infoflow6 ioctl 0x1234; allowxperm type0 type2:infoflow6 ioctl 0x1234; allowxperm type1 type3:infoflow6 ioctl 0x1234; allowxperm type2 type4:infoflow6 ioctl 0x1234; allowxperm type3 type5:infoflow6 ioctl 0x1234; allowxperm type4 type6:infoflow6 ioctl 0x1234; allowxperm type5 type7:infoflow6 ioctl 0x1234; allowxperm type6 type8:infoflow6 ioctl 0x1234; allowxperm type7 type9:infoflow6 ioctl 0x1234; allowxperm type8 type10:infoflow6 ioctl 0x1234; allowxperm type9 type11:infoflow6 ioctl 0x1234; allowxperm type10 type12:infoflow6 ioctl 0x1234; allowxperm type11 type13:infoflow6 ioctl 0x1234; allowxperm type12 type14:infoflow6 ioctl 0x1234; allowxperm type13 type15:infoflow6 ioctl 0x1234; allowxperm type14 type16:infoflow6 ioctl 0x1234; allowxperm type15 type17:infoflow6 ioctl 0x1234; allowxperm type16 type18:infoflow6 ioctl 0x1234; allowxperm type17 type19:infoflow6 ioctl 0x1234; allowxperm type18 type20:infoflow6 ioctl 0x1234; allowxperm type19 type21:infoflow6 ioctl 0x1234; allowxperm type20 type22:infoflow6 ioctl 0x1234; allowxperm type21 type23:infoflow6 ioctl 0x1234; allowxperm type22 type24:infoflow6 ioctl 0x1234; allowxperm type23 type25:infoflow6 ioctl 0x1234; allowxperm type24 type26:infoflow6 ioctl 0x1234; allowxperm type25 type27:infoflow6 ioctl 0x1234; allowxperm type26 type28:infoflow6 ioctl 0x1234; allowxperm type27 type29:infoflow6 ioctl 0x1234; allowxperm type28 type30:infoflow6 ioctl 0x1234; allowxperm type29 type31:infoflow6 ioctl 0x1234; allowxperm type30 type32:infoflow6 ioctl 0x1234; allowxperm type31 type33:infoflow6 ioctl 0x1234; allowxperm type32 type34:infoflow6 ioctl 0x1234; allowxperm type33 type35:infoflow6 ioctl 0x1234; allowxperm type34 type36:infoflow6 ioctl 0x1234; allowxperm type35 type37:infoflow6 ioctl 0x1234; allowxperm type36 type38:infoflow6 ioctl 0x1234; allowxperm type37 type39:infoflow6 ioctl 0x1234; allowxperm type38 type40:infoflow6 ioctl 0x1234; allowxperm type39 type41:infoflow6 ioctl 0x1234; allowxperm type40 type42:infoflow6 ioctl 0x1234; allowxperm type41 type43:infoflow6 ioctl 0x1234; # 181 auditallowxperm rules auditallowxperm type0 type2:infoflow6 ioctl 0x1234; auditallowxperm type1 type3:infoflow6 ioctl 0x1234; auditallowxperm type2 type4:infoflow6 ioctl 0x1234; auditallowxperm type3 type5:infoflow6 ioctl 0x1234; auditallowxperm type4 type6:infoflow6 ioctl 0x1234; auditallowxperm type5 type7:infoflow6 ioctl 0x1234; auditallowxperm type6 type8:infoflow6 ioctl 0x1234; auditallowxperm type7 type9:infoflow6 ioctl 0x1234; auditallowxperm type8 type10:infoflow6 ioctl 0x1234; auditallowxperm type9 type11:infoflow6 ioctl 0x1234; auditallowxperm type10 type12:infoflow6 ioctl 0x1234; auditallowxperm type11 type13:infoflow6 ioctl 0x1234; auditallowxperm type12 type14:infoflow6 ioctl 0x1234; auditallowxperm type13 type15:infoflow6 ioctl 0x1234; auditallowxperm type14 type16:infoflow6 ioctl 0x1234; auditallowxperm type15 type17:infoflow6 ioctl 0x1234; auditallowxperm type16 type18:infoflow6 ioctl 0x1234; auditallowxperm type17 type19:infoflow6 ioctl 0x1234; auditallowxperm type18 type20:infoflow6 ioctl 0x1234; auditallowxperm type19 type21:infoflow6 ioctl 0x1234; auditallowxperm type20 type22:infoflow6 ioctl 0x1234; auditallowxperm type21 type23:infoflow6 ioctl 0x1234; auditallowxperm type22 type24:infoflow6 ioctl 0x1234; auditallowxperm type23 type25:infoflow6 ioctl 0x1234; auditallowxperm type24 type26:infoflow6 ioctl 0x1234; auditallowxperm type25 type27:infoflow6 ioctl 0x1234; auditallowxperm type26 type28:infoflow6 ioctl 0x1234; auditallowxperm type27 type29:infoflow6 ioctl 0x1234; auditallowxperm type28 type30:infoflow6 ioctl 0x1234; auditallowxperm type29 type31:infoflow6 ioctl 0x1234; auditallowxperm type30 type32:infoflow6 ioctl 0x1234; auditallowxperm type31 type33:infoflow6 ioctl 0x1234; auditallowxperm type32 type34:infoflow6 ioctl 0x1234; auditallowxperm type33 type35:infoflow6 ioctl 0x1234; auditallowxperm type34 type36:infoflow6 ioctl 0x1234; auditallowxperm type35 type37:infoflow6 ioctl 0x1234; auditallowxperm type36 type38:infoflow6 ioctl 0x1234; auditallowxperm type37 type39:infoflow6 ioctl 0x1234; auditallowxperm type38 type40:infoflow6 ioctl 0x1234; auditallowxperm type39 type41:infoflow6 ioctl 0x1234; auditallowxperm type40 type42:infoflow6 ioctl 0x1234; auditallowxperm type41 type43:infoflow6 ioctl 0x1234; auditallowxperm type42 type44:infoflow6 ioctl 0x1234; auditallowxperm type43 type45:infoflow6 ioctl 0x1234; auditallowxperm type44 type46:infoflow6 ioctl 0x1234; auditallowxperm type45 type47:infoflow6 ioctl 0x1234; auditallowxperm type46 type48:infoflow6 ioctl 0x1234; auditallowxperm type47 type49:infoflow6 ioctl 0x1234; auditallowxperm type48 type50:infoflow6 ioctl 0x1234; auditallowxperm type49 type51:infoflow6 ioctl 0x1234; auditallowxperm type50 type52:infoflow6 ioctl 0x1234; auditallowxperm type51 type53:infoflow6 ioctl 0x1234; auditallowxperm type52 type54:infoflow6 ioctl 0x1234; auditallowxperm type53 type55:infoflow6 ioctl 0x1234; auditallowxperm type54 type56:infoflow6 ioctl 0x1234; auditallowxperm type55 type57:infoflow6 ioctl 0x1234; auditallowxperm type56 type58:infoflow6 ioctl 0x1234; auditallowxperm type57 type59:infoflow6 ioctl 0x1234; auditallowxperm type58 type60:infoflow6 ioctl 0x1234; auditallowxperm type59 type61:infoflow6 ioctl 0x1234; auditallowxperm type60 type62:infoflow6 ioctl 0x1234; auditallowxperm type61 type63:infoflow6 ioctl 0x1234; auditallowxperm type62 type64:infoflow6 ioctl 0x1234; auditallowxperm type63 type65:infoflow6 ioctl 0x1234; auditallowxperm type64 type66:infoflow6 ioctl 0x1234; auditallowxperm type65 type67:infoflow6 ioctl 0x1234; auditallowxperm type66 type68:infoflow6 ioctl 0x1234; auditallowxperm type67 type69:infoflow6 ioctl 0x1234; auditallowxperm type68 type70:infoflow6 ioctl 0x1234; auditallowxperm type69 type71:infoflow6 ioctl 0x1234; auditallowxperm type70 type72:infoflow6 ioctl 0x1234; auditallowxperm type71 type73:infoflow6 ioctl 0x1234; auditallowxperm type72 type74:infoflow6 ioctl 0x1234; auditallowxperm type73 type75:infoflow6 ioctl 0x1234; auditallowxperm type74 type76:infoflow6 ioctl 0x1234; auditallowxperm type75 type77:infoflow6 ioctl 0x1234; auditallowxperm type76 type78:infoflow6 ioctl 0x1234; auditallowxperm type77 type79:infoflow6 ioctl 0x1234; auditallowxperm type78 type80:infoflow6 ioctl 0x1234; auditallowxperm type79 type81:infoflow6 ioctl 0x1234; auditallowxperm type80 type82:infoflow6 ioctl 0x1234; auditallowxperm type81 type83:infoflow6 ioctl 0x1234; auditallowxperm type82 type84:infoflow6 ioctl 0x1234; auditallowxperm type83 type85:infoflow6 ioctl 0x1234; auditallowxperm type84 type86:infoflow6 ioctl 0x1234; auditallowxperm type85 type87:infoflow6 ioctl 0x1234; auditallowxperm type86 type88:infoflow6 ioctl 0x1234; auditallowxperm type87 type89:infoflow6 ioctl 0x1234; auditallowxperm type88 type90:infoflow6 ioctl 0x1234; auditallowxperm type89 type91:infoflow6 ioctl 0x1234; auditallowxperm type90 type92:infoflow6 ioctl 0x1234; auditallowxperm type91 type93:infoflow6 ioctl 0x1234; auditallowxperm type92 type94:infoflow6 ioctl 0x1234; auditallowxperm type93 type95:infoflow6 ioctl 0x1234; auditallowxperm type94 type96:infoflow6 ioctl 0x1234; auditallowxperm type95 type97:infoflow6 ioctl 0x1234; auditallowxperm type96 type98:infoflow6 ioctl 0x1234; auditallowxperm type97 type99:infoflow6 ioctl 0x1234; auditallowxperm type98 type100:infoflow6 ioctl 0x1234; auditallowxperm type99 type101:infoflow6 ioctl 0x1234; auditallowxperm type100 type102:infoflow6 ioctl 0x1234; auditallowxperm type101 type103:infoflow6 ioctl 0x1234; auditallowxperm type102 type104:infoflow6 ioctl 0x1234; auditallowxperm type103 type105:infoflow6 ioctl 0x1234; auditallowxperm type104 type106:infoflow6 ioctl 0x1234; auditallowxperm type105 type107:infoflow6 ioctl 0x1234; auditallowxperm type106 type108:infoflow6 ioctl 0x1234; auditallowxperm type107 type109:infoflow6 ioctl 0x1234; auditallowxperm type108 type110:infoflow6 ioctl 0x1234; auditallowxperm type109 type111:infoflow6 ioctl 0x1234; auditallowxperm type110 type112:infoflow6 ioctl 0x1234; auditallowxperm type111 type113:infoflow6 ioctl 0x1234; auditallowxperm type112 type114:infoflow6 ioctl 0x1234; auditallowxperm type113 type115:infoflow6 ioctl 0x1234; auditallowxperm type114 type116:infoflow6 ioctl 0x1234; auditallowxperm type115 type117:infoflow6 ioctl 0x1234; auditallowxperm type116 type118:infoflow6 ioctl 0x1234; auditallowxperm type117 type119:infoflow6 ioctl 0x1234; auditallowxperm type118 type120:infoflow6 ioctl 0x1234; auditallowxperm type119 type121:infoflow6 ioctl 0x1234; auditallowxperm type120 type122:infoflow6 ioctl 0x1234; auditallowxperm type121 type123:infoflow6 ioctl 0x1234; auditallowxperm type122 type124:infoflow6 ioctl 0x1234; auditallowxperm type123 type125:infoflow6 ioctl 0x1234; auditallowxperm type124 type126:infoflow6 ioctl 0x1234; auditallowxperm type125 type127:infoflow6 ioctl 0x1234; auditallowxperm type126 type128:infoflow6 ioctl 0x1234; auditallowxperm type127 type129:infoflow6 ioctl 0x1234; auditallowxperm type128 type130:infoflow6 ioctl 0x1234; auditallowxperm type129 type131:infoflow6 ioctl 0x1234; auditallowxperm type130 type132:infoflow6 ioctl 0x1234; auditallowxperm type131 type133:infoflow6 ioctl 0x1234; auditallowxperm type132 type134:infoflow6 ioctl 0x1234; auditallowxperm type133 type135:infoflow6 ioctl 0x1234; auditallowxperm type134 type136:infoflow6 ioctl 0x1234; auditallowxperm type135 type0:infoflow6 ioctl 0x1234; auditallowxperm type136 type1:infoflow6 ioctl 0x1234; auditallowxperm type0 type3:infoflow6 ioctl 0x1234; auditallowxperm type1 type4:infoflow6 ioctl 0x1234; auditallowxperm type2 type5:infoflow6 ioctl 0x1234; auditallowxperm type3 type6:infoflow6 ioctl 0x1234; auditallowxperm type4 type7:infoflow6 ioctl 0x1234; auditallowxperm type5 type8:infoflow6 ioctl 0x1234; auditallowxperm type6 type9:infoflow6 ioctl 0x1234; auditallowxperm type7 type10:infoflow6 ioctl 0x1234; auditallowxperm type8 type11:infoflow6 ioctl 0x1234; auditallowxperm type9 type12:infoflow6 ioctl 0x1234; auditallowxperm type10 type13:infoflow6 ioctl 0x1234; auditallowxperm type11 type14:infoflow6 ioctl 0x1234; auditallowxperm type12 type15:infoflow6 ioctl 0x1234; auditallowxperm type13 type16:infoflow6 ioctl 0x1234; auditallowxperm type14 type17:infoflow6 ioctl 0x1234; auditallowxperm type15 type18:infoflow6 ioctl 0x1234; auditallowxperm type16 type19:infoflow6 ioctl 0x1234; auditallowxperm type17 type20:infoflow6 ioctl 0x1234; auditallowxperm type18 type21:infoflow6 ioctl 0x1234; auditallowxperm type19 type22:infoflow6 ioctl 0x1234; auditallowxperm type20 type23:infoflow6 ioctl 0x1234; auditallowxperm type21 type24:infoflow6 ioctl 0x1234; auditallowxperm type22 type25:infoflow6 ioctl 0x1234; auditallowxperm type23 type26:infoflow6 ioctl 0x1234; auditallowxperm type24 type27:infoflow6 ioctl 0x1234; auditallowxperm type25 type28:infoflow6 ioctl 0x1234; auditallowxperm type26 type29:infoflow6 ioctl 0x1234; auditallowxperm type27 type30:infoflow6 ioctl 0x1234; auditallowxperm type28 type31:infoflow6 ioctl 0x1234; auditallowxperm type29 type32:infoflow6 ioctl 0x1234; auditallowxperm type30 type33:infoflow6 ioctl 0x1234; auditallowxperm type31 type34:infoflow6 ioctl 0x1234; auditallowxperm type32 type35:infoflow6 ioctl 0x1234; auditallowxperm type33 type36:infoflow6 ioctl 0x1234; auditallowxperm type34 type37:infoflow6 ioctl 0x1234; auditallowxperm type35 type38:infoflow6 ioctl 0x1234; auditallowxperm type36 type39:infoflow6 ioctl 0x1234; auditallowxperm type37 type40:infoflow6 ioctl 0x1234; auditallowxperm type38 type41:infoflow6 ioctl 0x1234; auditallowxperm type39 type42:infoflow6 ioctl 0x1234; auditallowxperm type40 type43:infoflow6 ioctl 0x1234; auditallowxperm type41 type44:infoflow6 ioctl 0x1234; auditallowxperm type42 type45:infoflow6 ioctl 0x1234; auditallowxperm type43 type46:infoflow6 ioctl 0x1234; # 191 neverallowxperm rules neverallowxperm type0 type4:infoflow6 ioctl 0x1234; neverallowxperm type1 type5:infoflow6 ioctl 0x1234; neverallowxperm type2 type6:infoflow6 ioctl 0x1234; neverallowxperm type3 type7:infoflow6 ioctl 0x1234; neverallowxperm type4 type8:infoflow6 ioctl 0x1234; neverallowxperm type5 type9:infoflow6 ioctl 0x1234; neverallowxperm type6 type10:infoflow6 ioctl 0x1234; neverallowxperm type7 type11:infoflow6 ioctl 0x1234; neverallowxperm type8 type12:infoflow6 ioctl 0x1234; neverallowxperm type9 type13:infoflow6 ioctl 0x1234; neverallowxperm type10 type14:infoflow6 ioctl 0x1234; neverallowxperm type11 type15:infoflow6 ioctl 0x1234; neverallowxperm type12 type16:infoflow6 ioctl 0x1234; neverallowxperm type13 type17:infoflow6 ioctl 0x1234; neverallowxperm type14 type18:infoflow6 ioctl 0x1234; neverallowxperm type15 type19:infoflow6 ioctl 0x1234; neverallowxperm type16 type20:infoflow6 ioctl 0x1234; neverallowxperm type17 type21:infoflow6 ioctl 0x1234; neverallowxperm type18 type22:infoflow6 ioctl 0x1234; neverallowxperm type19 type23:infoflow6 ioctl 0x1234; neverallowxperm type20 type24:infoflow6 ioctl 0x1234; neverallowxperm type21 type25:infoflow6 ioctl 0x1234; neverallowxperm type22 type26:infoflow6 ioctl 0x1234; neverallowxperm type23 type27:infoflow6 ioctl 0x1234; neverallowxperm type24 type28:infoflow6 ioctl 0x1234; neverallowxperm type25 type29:infoflow6 ioctl 0x1234; neverallowxperm type26 type30:infoflow6 ioctl 0x1234; neverallowxperm type27 type31:infoflow6 ioctl 0x1234; neverallowxperm type28 type32:infoflow6 ioctl 0x1234; neverallowxperm type29 type33:infoflow6 ioctl 0x1234; neverallowxperm type30 type34:infoflow6 ioctl 0x1234; neverallowxperm type31 type35:infoflow6 ioctl 0x1234; neverallowxperm type32 type36:infoflow6 ioctl 0x1234; neverallowxperm type33 type37:infoflow6 ioctl 0x1234; neverallowxperm type34 type38:infoflow6 ioctl 0x1234; neverallowxperm type35 type39:infoflow6 ioctl 0x1234; neverallowxperm type36 type40:infoflow6 ioctl 0x1234; neverallowxperm type37 type41:infoflow6 ioctl 0x1234; neverallowxperm type38 type42:infoflow6 ioctl 0x1234; neverallowxperm type39 type43:infoflow6 ioctl 0x1234; neverallowxperm type40 type44:infoflow6 ioctl 0x1234; neverallowxperm type41 type45:infoflow6 ioctl 0x1234; neverallowxperm type42 type46:infoflow6 ioctl 0x1234; neverallowxperm type43 type47:infoflow6 ioctl 0x1234; neverallowxperm type44 type48:infoflow6 ioctl 0x1234; neverallowxperm type45 type49:infoflow6 ioctl 0x1234; neverallowxperm type46 type50:infoflow6 ioctl 0x1234; neverallowxperm type47 type51:infoflow6 ioctl 0x1234; neverallowxperm type48 type52:infoflow6 ioctl 0x1234; neverallowxperm type49 type53:infoflow6 ioctl 0x1234; neverallowxperm type50 type54:infoflow6 ioctl 0x1234; neverallowxperm type51 type55:infoflow6 ioctl 0x1234; neverallowxperm type52 type56:infoflow6 ioctl 0x1234; neverallowxperm type53 type57:infoflow6 ioctl 0x1234; neverallowxperm type54 type58:infoflow6 ioctl 0x1234; neverallowxperm type55 type59:infoflow6 ioctl 0x1234; neverallowxperm type56 type60:infoflow6 ioctl 0x1234; neverallowxperm type57 type61:infoflow6 ioctl 0x1234; neverallowxperm type58 type62:infoflow6 ioctl 0x1234; neverallowxperm type59 type63:infoflow6 ioctl 0x1234; neverallowxperm type60 type64:infoflow6 ioctl 0x1234; neverallowxperm type61 type65:infoflow6 ioctl 0x1234; neverallowxperm type62 type66:infoflow6 ioctl 0x1234; neverallowxperm type63 type67:infoflow6 ioctl 0x1234; neverallowxperm type64 type68:infoflow6 ioctl 0x1234; neverallowxperm type65 type69:infoflow6 ioctl 0x1234; neverallowxperm type66 type70:infoflow6 ioctl 0x1234; neverallowxperm type67 type71:infoflow6 ioctl 0x1234; neverallowxperm type68 type72:infoflow6 ioctl 0x1234; neverallowxperm type69 type73:infoflow6 ioctl 0x1234; neverallowxperm type70 type74:infoflow6 ioctl 0x1234; neverallowxperm type71 type75:infoflow6 ioctl 0x1234; neverallowxperm type72 type76:infoflow6 ioctl 0x1234; neverallowxperm type73 type77:infoflow6 ioctl 0x1234; neverallowxperm type74 type78:infoflow6 ioctl 0x1234; neverallowxperm type75 type79:infoflow6 ioctl 0x1234; neverallowxperm type76 type80:infoflow6 ioctl 0x1234; neverallowxperm type77 type81:infoflow6 ioctl 0x1234; neverallowxperm type78 type82:infoflow6 ioctl 0x1234; neverallowxperm type79 type83:infoflow6 ioctl 0x1234; neverallowxperm type80 type84:infoflow6 ioctl 0x1234; neverallowxperm type81 type85:infoflow6 ioctl 0x1234; neverallowxperm type82 type86:infoflow6 ioctl 0x1234; neverallowxperm type83 type87:infoflow6 ioctl 0x1234; neverallowxperm type84 type88:infoflow6 ioctl 0x1234; neverallowxperm type85 type89:infoflow6 ioctl 0x1234; neverallowxperm type86 type90:infoflow6 ioctl 0x1234; neverallowxperm type87 type91:infoflow6 ioctl 0x1234; neverallowxperm type88 type92:infoflow6 ioctl 0x1234; neverallowxperm type89 type93:infoflow6 ioctl 0x1234; neverallowxperm type90 type94:infoflow6 ioctl 0x1234; neverallowxperm type91 type95:infoflow6 ioctl 0x1234; neverallowxperm type92 type96:infoflow6 ioctl 0x1234; neverallowxperm type93 type97:infoflow6 ioctl 0x1234; neverallowxperm type94 type98:infoflow6 ioctl 0x1234; neverallowxperm type95 type99:infoflow6 ioctl 0x1234; neverallowxperm type96 type100:infoflow6 ioctl 0x1234; neverallowxperm type97 type101:infoflow6 ioctl 0x1234; neverallowxperm type98 type102:infoflow6 ioctl 0x1234; neverallowxperm type99 type103:infoflow6 ioctl 0x1234; neverallowxperm type100 type104:infoflow6 ioctl 0x1234; neverallowxperm type101 type105:infoflow6 ioctl 0x1234; neverallowxperm type102 type106:infoflow6 ioctl 0x1234; neverallowxperm type103 type107:infoflow6 ioctl 0x1234; neverallowxperm type104 type108:infoflow6 ioctl 0x1234; neverallowxperm type105 type109:infoflow6 ioctl 0x1234; neverallowxperm type106 type110:infoflow6 ioctl 0x1234; neverallowxperm type107 type111:infoflow6 ioctl 0x1234; neverallowxperm type108 type112:infoflow6 ioctl 0x1234; neverallowxperm type109 type113:infoflow6 ioctl 0x1234; neverallowxperm type110 type114:infoflow6 ioctl 0x1234; neverallowxperm type111 type115:infoflow6 ioctl 0x1234; neverallowxperm type112 type116:infoflow6 ioctl 0x1234; neverallowxperm type113 type117:infoflow6 ioctl 0x1234; neverallowxperm type114 type118:infoflow6 ioctl 0x1234; neverallowxperm type115 type119:infoflow6 ioctl 0x1234; neverallowxperm type116 type120:infoflow6 ioctl 0x1234; neverallowxperm type117 type121:infoflow6 ioctl 0x1234; neverallowxperm type118 type122:infoflow6 ioctl 0x1234; neverallowxperm type119 type123:infoflow6 ioctl 0x1234; neverallowxperm type120 type124:infoflow6 ioctl 0x1234; neverallowxperm type121 type125:infoflow6 ioctl 0x1234; neverallowxperm type122 type126:infoflow6 ioctl 0x1234; neverallowxperm type123 type127:infoflow6 ioctl 0x1234; neverallowxperm type124 type128:infoflow6 ioctl 0x1234; neverallowxperm type125 type129:infoflow6 ioctl 0x1234; neverallowxperm type126 type130:infoflow6 ioctl 0x1234; neverallowxperm type127 type131:infoflow6 ioctl 0x1234; neverallowxperm type128 type132:infoflow6 ioctl 0x1234; neverallowxperm type129 type133:infoflow6 ioctl 0x1234; neverallowxperm type130 type134:infoflow6 ioctl 0x1234; neverallowxperm type131 type135:infoflow6 ioctl 0x1234; neverallowxperm type132 type136:infoflow6 ioctl 0x1234; neverallowxperm type133 type0:infoflow6 ioctl 0x1234; neverallowxperm type134 type1:infoflow6 ioctl 0x1234; neverallowxperm type135 type2:infoflow6 ioctl 0x1234; neverallowxperm type136 type3:infoflow6 ioctl 0x1234; neverallowxperm type0 type5:infoflow6 ioctl 0x1234; neverallowxperm type1 type6:infoflow6 ioctl 0x1234; neverallowxperm type2 type7:infoflow6 ioctl 0x1234; neverallowxperm type3 type8:infoflow6 ioctl 0x1234; neverallowxperm type4 type9:infoflow6 ioctl 0x1234; neverallowxperm type5 type10:infoflow6 ioctl 0x1234; neverallowxperm type6 type11:infoflow6 ioctl 0x1234; neverallowxperm type7 type12:infoflow6 ioctl 0x1234; neverallowxperm type8 type13:infoflow6 ioctl 0x1234; neverallowxperm type9 type14:infoflow6 ioctl 0x1234; neverallowxperm type10 type15:infoflow6 ioctl 0x1234; neverallowxperm type11 type16:infoflow6 ioctl 0x1234; neverallowxperm type12 type17:infoflow6 ioctl 0x1234; neverallowxperm type13 type18:infoflow6 ioctl 0x1234; neverallowxperm type14 type19:infoflow6 ioctl 0x1234; neverallowxperm type15 type20:infoflow6 ioctl 0x1234; neverallowxperm type16 type21:infoflow6 ioctl 0x1234; neverallowxperm type17 type22:infoflow6 ioctl 0x1234; neverallowxperm type18 type23:infoflow6 ioctl 0x1234; neverallowxperm type19 type24:infoflow6 ioctl 0x1234; neverallowxperm type20 type25:infoflow6 ioctl 0x1234; neverallowxperm type21 type26:infoflow6 ioctl 0x1234; neverallowxperm type22 type27:infoflow6 ioctl 0x1234; neverallowxperm type23 type28:infoflow6 ioctl 0x1234; neverallowxperm type24 type29:infoflow6 ioctl 0x1234; neverallowxperm type25 type30:infoflow6 ioctl 0x1234; neverallowxperm type26 type31:infoflow6 ioctl 0x1234; neverallowxperm type27 type32:infoflow6 ioctl 0x1234; neverallowxperm type28 type33:infoflow6 ioctl 0x1234; neverallowxperm type29 type34:infoflow6 ioctl 0x1234; neverallowxperm type30 type35:infoflow6 ioctl 0x1234; neverallowxperm type31 type36:infoflow6 ioctl 0x1234; neverallowxperm type32 type37:infoflow6 ioctl 0x1234; neverallowxperm type33 type38:infoflow6 ioctl 0x1234; neverallowxperm type34 type39:infoflow6 ioctl 0x1234; neverallowxperm type35 type40:infoflow6 ioctl 0x1234; neverallowxperm type36 type41:infoflow6 ioctl 0x1234; neverallowxperm type37 type42:infoflow6 ioctl 0x1234; neverallowxperm type38 type43:infoflow6 ioctl 0x1234; neverallowxperm type39 type44:infoflow6 ioctl 0x1234; neverallowxperm type40 type45:infoflow6 ioctl 0x1234; neverallowxperm type41 type46:infoflow6 ioctl 0x1234; neverallowxperm type42 type47:infoflow6 ioctl 0x1234; neverallowxperm type43 type48:infoflow6 ioctl 0x1234; neverallowxperm type44 type49:infoflow6 ioctl 0x1234; neverallowxperm type45 type50:infoflow6 ioctl 0x1234; neverallowxperm type46 type51:infoflow6 ioctl 0x1234; neverallowxperm type47 type52:infoflow6 ioctl 0x1234; neverallowxperm type48 type53:infoflow6 ioctl 0x1234; neverallowxperm type49 type54:infoflow6 ioctl 0x1234; neverallowxperm type50 type55:infoflow6 ioctl 0x1234; neverallowxperm type51 type56:infoflow6 ioctl 0x1234; neverallowxperm type52 type57:infoflow6 ioctl 0x1234; neverallowxperm type53 type58:infoflow6 ioctl 0x1234; # 193 dontauditxperm rules dontauditxperm type0 type5:infoflow6 ioctl 0x1234; dontauditxperm type1 type6:infoflow6 ioctl 0x1234; dontauditxperm type2 type7:infoflow6 ioctl 0x1234; dontauditxperm type3 type8:infoflow6 ioctl 0x1234; dontauditxperm type4 type9:infoflow6 ioctl 0x1234; dontauditxperm type5 type10:infoflow6 ioctl 0x1234; dontauditxperm type6 type11:infoflow6 ioctl 0x1234; dontauditxperm type7 type12:infoflow6 ioctl 0x1234; dontauditxperm type8 type13:infoflow6 ioctl 0x1234; dontauditxperm type9 type14:infoflow6 ioctl 0x1234; dontauditxperm type10 type15:infoflow6 ioctl 0x1234; dontauditxperm type11 type16:infoflow6 ioctl 0x1234; dontauditxperm type12 type17:infoflow6 ioctl 0x1234; dontauditxperm type13 type18:infoflow6 ioctl 0x1234; dontauditxperm type14 type19:infoflow6 ioctl 0x1234; dontauditxperm type15 type20:infoflow6 ioctl 0x1234; dontauditxperm type16 type21:infoflow6 ioctl 0x1234; dontauditxperm type17 type22:infoflow6 ioctl 0x1234; dontauditxperm type18 type23:infoflow6 ioctl 0x1234; dontauditxperm type19 type24:infoflow6 ioctl 0x1234; dontauditxperm type20 type25:infoflow6 ioctl 0x1234; dontauditxperm type21 type26:infoflow6 ioctl 0x1234; dontauditxperm type22 type27:infoflow6 ioctl 0x1234; dontauditxperm type23 type28:infoflow6 ioctl 0x1234; dontauditxperm type24 type29:infoflow6 ioctl 0x1234; dontauditxperm type25 type30:infoflow6 ioctl 0x1234; dontauditxperm type26 type31:infoflow6 ioctl 0x1234; dontauditxperm type27 type32:infoflow6 ioctl 0x1234; dontauditxperm type28 type33:infoflow6 ioctl 0x1234; dontauditxperm type29 type34:infoflow6 ioctl 0x1234; dontauditxperm type30 type35:infoflow6 ioctl 0x1234; dontauditxperm type31 type36:infoflow6 ioctl 0x1234; dontauditxperm type32 type37:infoflow6 ioctl 0x1234; dontauditxperm type33 type38:infoflow6 ioctl 0x1234; dontauditxperm type34 type39:infoflow6 ioctl 0x1234; dontauditxperm type35 type40:infoflow6 ioctl 0x1234; dontauditxperm type36 type41:infoflow6 ioctl 0x1234; dontauditxperm type37 type42:infoflow6 ioctl 0x1234; dontauditxperm type38 type43:infoflow6 ioctl 0x1234; dontauditxperm type39 type44:infoflow6 ioctl 0x1234; dontauditxperm type40 type45:infoflow6 ioctl 0x1234; dontauditxperm type41 type46:infoflow6 ioctl 0x1234; dontauditxperm type42 type47:infoflow6 ioctl 0x1234; dontauditxperm type43 type48:infoflow6 ioctl 0x1234; dontauditxperm type44 type49:infoflow6 ioctl 0x1234; dontauditxperm type45 type50:infoflow6 ioctl 0x1234; dontauditxperm type46 type51:infoflow6 ioctl 0x1234; dontauditxperm type47 type52:infoflow6 ioctl 0x1234; dontauditxperm type48 type53:infoflow6 ioctl 0x1234; dontauditxperm type49 type54:infoflow6 ioctl 0x1234; dontauditxperm type50 type55:infoflow6 ioctl 0x1234; dontauditxperm type51 type56:infoflow6 ioctl 0x1234; dontauditxperm type52 type57:infoflow6 ioctl 0x1234; dontauditxperm type53 type58:infoflow6 ioctl 0x1234; dontauditxperm type54 type59:infoflow6 ioctl 0x1234; dontauditxperm type55 type60:infoflow6 ioctl 0x1234; dontauditxperm type56 type61:infoflow6 ioctl 0x1234; dontauditxperm type57 type62:infoflow6 ioctl 0x1234; dontauditxperm type58 type63:infoflow6 ioctl 0x1234; dontauditxperm type59 type64:infoflow6 ioctl 0x1234; dontauditxperm type60 type65:infoflow6 ioctl 0x1234; dontauditxperm type61 type66:infoflow6 ioctl 0x1234; dontauditxperm type62 type67:infoflow6 ioctl 0x1234; dontauditxperm type63 type68:infoflow6 ioctl 0x1234; dontauditxperm type64 type69:infoflow6 ioctl 0x1234; dontauditxperm type65 type70:infoflow6 ioctl 0x1234; dontauditxperm type66 type71:infoflow6 ioctl 0x1234; dontauditxperm type67 type72:infoflow6 ioctl 0x1234; dontauditxperm type68 type73:infoflow6 ioctl 0x1234; dontauditxperm type69 type74:infoflow6 ioctl 0x1234; dontauditxperm type70 type75:infoflow6 ioctl 0x1234; dontauditxperm type71 type76:infoflow6 ioctl 0x1234; dontauditxperm type72 type77:infoflow6 ioctl 0x1234; dontauditxperm type73 type78:infoflow6 ioctl 0x1234; dontauditxperm type74 type79:infoflow6 ioctl 0x1234; dontauditxperm type75 type80:infoflow6 ioctl 0x1234; dontauditxperm type76 type81:infoflow6 ioctl 0x1234; dontauditxperm type77 type82:infoflow6 ioctl 0x1234; dontauditxperm type78 type83:infoflow6 ioctl 0x1234; dontauditxperm type79 type84:infoflow6 ioctl 0x1234; dontauditxperm type80 type85:infoflow6 ioctl 0x1234; dontauditxperm type81 type86:infoflow6 ioctl 0x1234; dontauditxperm type82 type87:infoflow6 ioctl 0x1234; dontauditxperm type83 type88:infoflow6 ioctl 0x1234; dontauditxperm type84 type89:infoflow6 ioctl 0x1234; dontauditxperm type85 type90:infoflow6 ioctl 0x1234; dontauditxperm type86 type91:infoflow6 ioctl 0x1234; dontauditxperm type87 type92:infoflow6 ioctl 0x1234; dontauditxperm type88 type93:infoflow6 ioctl 0x1234; dontauditxperm type89 type94:infoflow6 ioctl 0x1234; dontauditxperm type90 type95:infoflow6 ioctl 0x1234; dontauditxperm type91 type96:infoflow6 ioctl 0x1234; dontauditxperm type92 type97:infoflow6 ioctl 0x1234; dontauditxperm type93 type98:infoflow6 ioctl 0x1234; dontauditxperm type94 type99:infoflow6 ioctl 0x1234; dontauditxperm type95 type100:infoflow6 ioctl 0x1234; dontauditxperm type96 type101:infoflow6 ioctl 0x1234; dontauditxperm type97 type102:infoflow6 ioctl 0x1234; dontauditxperm type98 type103:infoflow6 ioctl 0x1234; dontauditxperm type99 type104:infoflow6 ioctl 0x1234; dontauditxperm type100 type105:infoflow6 ioctl 0x1234; dontauditxperm type101 type106:infoflow6 ioctl 0x1234; dontauditxperm type102 type107:infoflow6 ioctl 0x1234; dontauditxperm type103 type108:infoflow6 ioctl 0x1234; dontauditxperm type104 type109:infoflow6 ioctl 0x1234; dontauditxperm type105 type110:infoflow6 ioctl 0x1234; dontauditxperm type106 type111:infoflow6 ioctl 0x1234; dontauditxperm type107 type112:infoflow6 ioctl 0x1234; dontauditxperm type108 type113:infoflow6 ioctl 0x1234; dontauditxperm type109 type114:infoflow6 ioctl 0x1234; dontauditxperm type110 type115:infoflow6 ioctl 0x1234; dontauditxperm type111 type116:infoflow6 ioctl 0x1234; dontauditxperm type112 type117:infoflow6 ioctl 0x1234; dontauditxperm type113 type118:infoflow6 ioctl 0x1234; dontauditxperm type114 type119:infoflow6 ioctl 0x1234; dontauditxperm type115 type120:infoflow6 ioctl 0x1234; dontauditxperm type116 type121:infoflow6 ioctl 0x1234; dontauditxperm type117 type122:infoflow6 ioctl 0x1234; dontauditxperm type118 type123:infoflow6 ioctl 0x1234; dontauditxperm type119 type124:infoflow6 ioctl 0x1234; dontauditxperm type120 type125:infoflow6 ioctl 0x1234; dontauditxperm type121 type126:infoflow6 ioctl 0x1234; dontauditxperm type122 type127:infoflow6 ioctl 0x1234; dontauditxperm type123 type128:infoflow6 ioctl 0x1234; dontauditxperm type124 type129:infoflow6 ioctl 0x1234; dontauditxperm type125 type130:infoflow6 ioctl 0x1234; dontauditxperm type126 type131:infoflow6 ioctl 0x1234; dontauditxperm type127 type132:infoflow6 ioctl 0x1234; dontauditxperm type128 type133:infoflow6 ioctl 0x1234; dontauditxperm type129 type134:infoflow6 ioctl 0x1234; dontauditxperm type130 type135:infoflow6 ioctl 0x1234; dontauditxperm type131 type136:infoflow6 ioctl 0x1234; dontauditxperm type132 type0:infoflow6 ioctl 0x1234; dontauditxperm type133 type1:infoflow6 ioctl 0x1234; dontauditxperm type134 type2:infoflow6 ioctl 0x1234; dontauditxperm type135 type3:infoflow6 ioctl 0x1234; dontauditxperm type136 type4:infoflow6 ioctl 0x1234; dontauditxperm type0 type6:infoflow6 ioctl 0x1234; dontauditxperm type1 type7:infoflow6 ioctl 0x1234; dontauditxperm type2 type8:infoflow6 ioctl 0x1234; dontauditxperm type3 type9:infoflow6 ioctl 0x1234; dontauditxperm type4 type10:infoflow6 ioctl 0x1234; dontauditxperm type5 type11:infoflow6 ioctl 0x1234; dontauditxperm type6 type12:infoflow6 ioctl 0x1234; dontauditxperm type7 type13:infoflow6 ioctl 0x1234; dontauditxperm type8 type14:infoflow6 ioctl 0x1234; dontauditxperm type9 type15:infoflow6 ioctl 0x1234; dontauditxperm type10 type16:infoflow6 ioctl 0x1234; dontauditxperm type11 type17:infoflow6 ioctl 0x1234; dontauditxperm type12 type18:infoflow6 ioctl 0x1234; dontauditxperm type13 type19:infoflow6 ioctl 0x1234; dontauditxperm type14 type20:infoflow6 ioctl 0x1234; dontauditxperm type15 type21:infoflow6 ioctl 0x1234; dontauditxperm type16 type22:infoflow6 ioctl 0x1234; dontauditxperm type17 type23:infoflow6 ioctl 0x1234; dontauditxperm type18 type24:infoflow6 ioctl 0x1234; dontauditxperm type19 type25:infoflow6 ioctl 0x1234; dontauditxperm type20 type26:infoflow6 ioctl 0x1234; dontauditxperm type21 type27:infoflow6 ioctl 0x1234; dontauditxperm type22 type28:infoflow6 ioctl 0x1234; dontauditxperm type23 type29:infoflow6 ioctl 0x1234; dontauditxperm type24 type30:infoflow6 ioctl 0x1234; dontauditxperm type25 type31:infoflow6 ioctl 0x1234; dontauditxperm type26 type32:infoflow6 ioctl 0x1234; dontauditxperm type27 type33:infoflow6 ioctl 0x1234; dontauditxperm type28 type34:infoflow6 ioctl 0x1234; dontauditxperm type29 type35:infoflow6 ioctl 0x1234; dontauditxperm type30 type36:infoflow6 ioctl 0x1234; dontauditxperm type31 type37:infoflow6 ioctl 0x1234; dontauditxperm type32 type38:infoflow6 ioctl 0x1234; dontauditxperm type33 type39:infoflow6 ioctl 0x1234; dontauditxperm type34 type40:infoflow6 ioctl 0x1234; dontauditxperm type35 type41:infoflow6 ioctl 0x1234; dontauditxperm type36 type42:infoflow6 ioctl 0x1234; dontauditxperm type37 type43:infoflow6 ioctl 0x1234; dontauditxperm type38 type44:infoflow6 ioctl 0x1234; dontauditxperm type39 type45:infoflow6 ioctl 0x1234; dontauditxperm type40 type46:infoflow6 ioctl 0x1234; dontauditxperm type41 type47:infoflow6 ioctl 0x1234; dontauditxperm type42 type48:infoflow6 ioctl 0x1234; dontauditxperm type43 type49:infoflow6 ioctl 0x1234; dontauditxperm type44 type50:infoflow6 ioctl 0x1234; dontauditxperm type45 type51:infoflow6 ioctl 0x1234; dontauditxperm type46 type52:infoflow6 ioctl 0x1234; dontauditxperm type47 type53:infoflow6 ioctl 0x1234; dontauditxperm type48 type54:infoflow6 ioctl 0x1234; dontauditxperm type49 type55:infoflow6 ioctl 0x1234; dontauditxperm type50 type56:infoflow6 ioctl 0x1234; dontauditxperm type51 type57:infoflow6 ioctl 0x1234; dontauditxperm type52 type58:infoflow6 ioctl 0x1234; dontauditxperm type53 type59:infoflow6 ioctl 0x1234; dontauditxperm type54 type60:infoflow6 ioctl 0x1234; dontauditxperm type55 type61:infoflow6 ioctl 0x1234; ################################################################################ # 101 users user user0 roles role0 level s4:c5 range s4:c5; user user1 roles role0 level s4:c5 range s4:c5; user user2 roles role0 level s4:c5 range s4:c5; user user3 roles role0 level s4:c5 range s4:c5; user user4 roles role0 level s4:c5 range s4:c5; user user5 roles role0 level s4:c5 range s4:c5; user user6 roles role0 level s4:c5 range s4:c5; user user7 roles role0 level s4:c5 range s4:c5; user user8 roles role0 level s4:c5 range s4:c5; user user9 roles role0 level s4:c5 range s4:c5; user user10 roles role0 level s4:c5 range s4:c5; user user11 roles role0 level s4:c5 range s4:c5; user user12 roles role0 level s4:c5 range s4:c5; user user13 roles role0 level s4:c5 range s4:c5; user user14 roles role0 level s4:c5 range s4:c5; user user15 roles role0 level s4:c5 range s4:c5; user user16 roles role0 level s4:c5 range s4:c5; user user17 roles role0 level s4:c5 range s4:c5; user user18 roles role0 level s4:c5 range s4:c5; user user19 roles role0 level s4:c5 range s4:c5; user user20 roles role0 level s4:c5 range s4:c5; user user21 roles role0 level s4:c5 range s4:c5; user user22 roles role0 level s4:c5 range s4:c5; user user23 roles role0 level s4:c5 range s4:c5; user user24 roles role0 level s4:c5 range s4:c5; user user25 roles role0 level s4:c5 range s4:c5; user user26 roles role0 level s4:c5 range s4:c5; user user27 roles role0 level s4:c5 range s4:c5; user user28 roles role0 level s4:c5 range s4:c5; user user29 roles role0 level s4:c5 range s4:c5; user user30 roles role0 level s4:c5 range s4:c5; user user31 roles role0 level s4:c5 range s4:c5; user user32 roles role0 level s4:c5 range s4:c5; user user33 roles role0 level s4:c5 range s4:c5; user user34 roles role0 level s4:c5 range s4:c5; user user35 roles role0 level s4:c5 range s4:c5; user user36 roles role0 level s4:c5 range s4:c5; user user37 roles role0 level s4:c5 range s4:c5; user user38 roles role0 level s4:c5 range s4:c5; user user39 roles role0 level s4:c5 range s4:c5; user user40 roles role0 level s4:c5 range s4:c5; user user41 roles role0 level s4:c5 range s4:c5; user user42 roles role0 level s4:c5 range s4:c5; user user43 roles role0 level s4:c5 range s4:c5; user user44 roles role0 level s4:c5 range s4:c5; user user45 roles role0 level s4:c5 range s4:c5; user user46 roles role0 level s4:c5 range s4:c5; user user47 roles role0 level s4:c5 range s4:c5; user user48 roles role0 level s4:c5 range s4:c5; user user49 roles role0 level s4:c5 range s4:c5; user user50 roles role0 level s4:c5 range s4:c5; user user51 roles role0 level s4:c5 range s4:c5; user user52 roles role0 level s4:c5 range s4:c5; user user53 roles role0 level s4:c5 range s4:c5; user user54 roles role0 level s4:c5 range s4:c5; user user55 roles role0 level s4:c5 range s4:c5; user user56 roles role0 level s4:c5 range s4:c5; user user57 roles role0 level s4:c5 range s4:c5; user user58 roles role0 level s4:c5 range s4:c5; user user59 roles role0 level s4:c5 range s4:c5; user user60 roles role0 level s4:c5 range s4:c5; user user61 roles role0 level s4:c5 range s4:c5; user user62 roles role0 level s4:c5 range s4:c5; user user63 roles role0 level s4:c5 range s4:c5; user user64 roles role0 level s4:c5 range s4:c5; user user65 roles role0 level s4:c5 range s4:c5; user user66 roles role0 level s4:c5 range s4:c5; user user67 roles role0 level s4:c5 range s4:c5; user user68 roles role0 level s4:c5 range s4:c5; user user69 roles role0 level s4:c5 range s4:c5; user user70 roles role0 level s4:c5 range s4:c5; user user71 roles role0 level s4:c5 range s4:c5; user user72 roles role0 level s4:c5 range s4:c5; user user73 roles role0 level s4:c5 range s4:c5; user user74 roles role0 level s4:c5 range s4:c5; user user75 roles role0 level s4:c5 range s4:c5; user user76 roles role0 level s4:c5 range s4:c5; user user77 roles role0 level s4:c5 range s4:c5; user user78 roles role0 level s4:c5 range s4:c5; user user79 roles role0 level s4:c5 range s4:c5; user user80 roles role0 level s4:c5 range s4:c5; user user81 roles role0 level s4:c5 range s4:c5; user user82 roles role0 level s4:c5 range s4:c5; user user83 roles role0 level s4:c5 range s4:c5; user user84 roles role0 level s4:c5 range s4:c5; user user85 roles role0 level s4:c5 range s4:c5; user user86 roles role0 level s4:c5 range s4:c5; user user87 roles role0 level s4:c5 range s4:c5; user user88 roles role0 level s4:c5 range s4:c5; user user89 roles role0 level s4:c5 range s4:c5; user user90 roles role0 level s4:c5 range s4:c5; user user91 roles role0 level s4:c5 range s4:c5; user user92 roles role0 level s4:c5 range s4:c5; user user93 roles role0 level s4:c5 range s4:c5; user user94 roles role0 level s4:c5 range s4:c5; user user95 roles role0 level s4:c5 range s4:c5; user user96 roles role0 level s4:c5 range s4:c5; user user97 roles role0 level s4:c5 range s4:c5; user user98 roles role0 level s4:c5 range s4:c5; user user99 roles role0 level s4:c5 range s4:c5; user user100 roles role0 level s4:c5 range s4:c5; # 19 normal constraints constrain infoflow low_w ((u1 eq u2) or (t1 == attr1)); constrain infoflow low_r ((u1 eq u2) or (t1 == attr2)); constrain infoflow low_none ((u1 eq u2) or (t1 == attr3)); constrain infoflow2 med_r ((u1 eq u2) or (t1 == attr4)); constrain infoflow2 med_w ((u1 eq u2) or (t1 == attr5)); constrain infoflow2 med_none ((u1 eq u2) or (t1 == attr6)); constrain infoflow2 med_both ((u1 eq u2) or (t1 == attr7)); constrain infoflow2 med_fifth ((u1 eq u2) or (t1 == attr8)); constrain infoflow2 super_r ((u1 eq u2) or (t1 == attr9)); constrain infoflow2 super_w ((u1 eq u2) or (t1 == attr10)); constrain infoflow4 hi_w ((u1 eq u2) or (t1 == attr11)); constrain infoflow4 hi_r ((u1 eq u2) or (t1 == attr12)); constrain infoflow4 hi_third ((u1 eq u2) or (t1 == attr13)); constrain infoflow4 hi_fourth ((u1 eq u2) or (t1 == attr14)); constrain infoflow4 hi_fifth ((u1 eq u2) or (t1 == attr15)); constrain infoflow4 hi_sixth ((u1 eq u2) or (t1 == attr16)); constrain infoflow4 hi_seventh ((u1 eq u2) or (t1 == attr17)); constrain infoflow4 super_both ((u1 eq u2) or (t1 == attr18)); constrain infoflow5 hi_w ((u1 eq u2) or (t1 == attr19)); # 5 validatetrans validatetrans { infoflow infoflow2 infoflow3 infoflow4 infoflow5 } (u1 == u2); # 11 initial SIDs sid sid_one user0:role0:type0:s4:c5 sid sid_two user0:role0:type0:s4:c5 sid sid_three user0:role0:type0:s4:c5 sid sid_four user0:role0:type0:s4:c5 sid sid_five user0:role0:type0:s4:c5 sid sid_six user0:role0:type0:s4:c5 sid sid_seven user0:role0:type0:s4:c5 sid sid_eight user0:role0:type0:s4:c5 sid sid_nine user0:role0:type0:s4:c5 sid sid_ten user0:role0:type0:s4:c5 sid sid_eleven user0:role0:type0:s4:c5 # 149 fs_use fs_use_trans fs0 user0:object_r:type0:s4:c5; fs_use_xattr fs1 user0:object_r:type0:s4:c5; fs_use_task fs2 user0:object_r:type0:s4:c5; fs_use_trans fs3 user0:object_r:type0:s4:c5; fs_use_xattr fs4 user0:object_r:type0:s4:c5; fs_use_task fs5 user0:object_r:type0:s4:c5; fs_use_trans fs6 user0:object_r:type0:s4:c5; fs_use_xattr fs7 user0:object_r:type0:s4:c5; fs_use_task fs8 user0:object_r:type0:s4:c5; fs_use_trans fs9 user0:object_r:type0:s4:c5; fs_use_xattr fs10 user0:object_r:type0:s4:c5; fs_use_task fs11 user0:object_r:type0:s4:c5; fs_use_trans fs12 user0:object_r:type0:s4:c5; fs_use_xattr fs13 user0:object_r:type0:s4:c5; fs_use_task fs14 user0:object_r:type0:s4:c5; fs_use_trans fs15 user0:object_r:type0:s4:c5; fs_use_xattr fs16 user0:object_r:type0:s4:c5; fs_use_task fs17 user0:object_r:type0:s4:c5; fs_use_trans fs18 user0:object_r:type0:s4:c5; fs_use_xattr fs19 user0:object_r:type0:s4:c5; fs_use_task fs20 user0:object_r:type0:s4:c5; fs_use_trans fs21 user0:object_r:type0:s4:c5; fs_use_xattr fs22 user0:object_r:type0:s4:c5; fs_use_task fs23 user0:object_r:type0:s4:c5; fs_use_trans fs24 user0:object_r:type0:s4:c5; fs_use_xattr fs25 user0:object_r:type0:s4:c5; fs_use_task fs26 user0:object_r:type0:s4:c5; fs_use_trans fs27 user0:object_r:type0:s4:c5; fs_use_xattr fs28 user0:object_r:type0:s4:c5; fs_use_task fs29 user0:object_r:type0:s4:c5; fs_use_trans fs30 user0:object_r:type0:s4:c5; fs_use_xattr fs31 user0:object_r:type0:s4:c5; fs_use_task fs32 user0:object_r:type0:s4:c5; fs_use_trans fs33 user0:object_r:type0:s4:c5; fs_use_xattr fs34 user0:object_r:type0:s4:c5; fs_use_task fs35 user0:object_r:type0:s4:c5; fs_use_trans fs36 user0:object_r:type0:s4:c5; fs_use_xattr fs37 user0:object_r:type0:s4:c5; fs_use_task fs38 user0:object_r:type0:s4:c5; fs_use_trans fs39 user0:object_r:type0:s4:c5; fs_use_xattr fs40 user0:object_r:type0:s4:c5; fs_use_task fs41 user0:object_r:type0:s4:c5; fs_use_trans fs42 user0:object_r:type0:s4:c5; fs_use_xattr fs43 user0:object_r:type0:s4:c5; fs_use_task fs44 user0:object_r:type0:s4:c5; fs_use_trans fs45 user0:object_r:type0:s4:c5; fs_use_xattr fs46 user0:object_r:type0:s4:c5; fs_use_task fs47 user0:object_r:type0:s4:c5; fs_use_trans fs48 user0:object_r:type0:s4:c5; fs_use_xattr fs49 user0:object_r:type0:s4:c5; fs_use_task fs50 user0:object_r:type0:s4:c5; fs_use_trans fs51 user0:object_r:type0:s4:c5; fs_use_xattr fs52 user0:object_r:type0:s4:c5; fs_use_task fs53 user0:object_r:type0:s4:c5; fs_use_trans fs54 user0:object_r:type0:s4:c5; fs_use_xattr fs55 user0:object_r:type0:s4:c5; fs_use_task fs56 user0:object_r:type0:s4:c5; fs_use_trans fs57 user0:object_r:type0:s4:c5; fs_use_xattr fs58 user0:object_r:type0:s4:c5; fs_use_task fs59 user0:object_r:type0:s4:c5; fs_use_trans fs60 user0:object_r:type0:s4:c5; fs_use_xattr fs61 user0:object_r:type0:s4:c5; fs_use_task fs62 user0:object_r:type0:s4:c5; fs_use_trans fs63 user0:object_r:type0:s4:c5; fs_use_xattr fs64 user0:object_r:type0:s4:c5; fs_use_task fs65 user0:object_r:type0:s4:c5; fs_use_trans fs66 user0:object_r:type0:s4:c5; fs_use_xattr fs67 user0:object_r:type0:s4:c5; fs_use_task fs68 user0:object_r:type0:s4:c5; fs_use_trans fs69 user0:object_r:type0:s4:c5; fs_use_xattr fs70 user0:object_r:type0:s4:c5; fs_use_task fs71 user0:object_r:type0:s4:c5; fs_use_trans fs72 user0:object_r:type0:s4:c5; fs_use_xattr fs73 user0:object_r:type0:s4:c5; fs_use_task fs74 user0:object_r:type0:s4:c5; fs_use_trans fs75 user0:object_r:type0:s4:c5; fs_use_xattr fs76 user0:object_r:type0:s4:c5; fs_use_task fs77 user0:object_r:type0:s4:c5; fs_use_trans fs78 user0:object_r:type0:s4:c5; fs_use_xattr fs79 user0:object_r:type0:s4:c5; fs_use_task fs80 user0:object_r:type0:s4:c5; fs_use_trans fs81 user0:object_r:type0:s4:c5; fs_use_xattr fs82 user0:object_r:type0:s4:c5; fs_use_task fs83 user0:object_r:type0:s4:c5; fs_use_trans fs84 user0:object_r:type0:s4:c5; fs_use_xattr fs85 user0:object_r:type0:s4:c5; fs_use_task fs86 user0:object_r:type0:s4:c5; fs_use_trans fs87 user0:object_r:type0:s4:c5; fs_use_xattr fs88 user0:object_r:type0:s4:c5; fs_use_task fs89 user0:object_r:type0:s4:c5; fs_use_trans fs90 user0:object_r:type0:s4:c5; fs_use_xattr fs91 user0:object_r:type0:s4:c5; fs_use_task fs92 user0:object_r:type0:s4:c5; fs_use_trans fs93 user0:object_r:type0:s4:c5; fs_use_xattr fs94 user0:object_r:type0:s4:c5; fs_use_task fs95 user0:object_r:type0:s4:c5; fs_use_trans fs96 user0:object_r:type0:s4:c5; fs_use_xattr fs97 user0:object_r:type0:s4:c5; fs_use_task fs98 user0:object_r:type0:s4:c5; fs_use_trans fs99 user0:object_r:type0:s4:c5; fs_use_xattr fs100 user0:object_r:type0:s4:c5; fs_use_task fs101 user0:object_r:type0:s4:c5; fs_use_trans fs102 user0:object_r:type0:s4:c5; fs_use_xattr fs103 user0:object_r:type0:s4:c5; fs_use_task fs104 user0:object_r:type0:s4:c5; fs_use_trans fs105 user0:object_r:type0:s4:c5; fs_use_xattr fs106 user0:object_r:type0:s4:c5; fs_use_task fs107 user0:object_r:type0:s4:c5; fs_use_trans fs108 user0:object_r:type0:s4:c5; fs_use_xattr fs109 user0:object_r:type0:s4:c5; fs_use_task fs110 user0:object_r:type0:s4:c5; fs_use_trans fs111 user0:object_r:type0:s4:c5; fs_use_xattr fs112 user0:object_r:type0:s4:c5; fs_use_task fs113 user0:object_r:type0:s4:c5; fs_use_trans fs114 user0:object_r:type0:s4:c5; fs_use_xattr fs115 user0:object_r:type0:s4:c5; fs_use_task fs116 user0:object_r:type0:s4:c5; fs_use_trans fs117 user0:object_r:type0:s4:c5; fs_use_xattr fs118 user0:object_r:type0:s4:c5; fs_use_task fs119 user0:object_r:type0:s4:c5; fs_use_trans fs120 user0:object_r:type0:s4:c5; fs_use_xattr fs121 user0:object_r:type0:s4:c5; fs_use_task fs122 user0:object_r:type0:s4:c5; fs_use_trans fs123 user0:object_r:type0:s4:c5; fs_use_xattr fs124 user0:object_r:type0:s4:c5; fs_use_task fs125 user0:object_r:type0:s4:c5; fs_use_trans fs126 user0:object_r:type0:s4:c5; fs_use_xattr fs127 user0:object_r:type0:s4:c5; fs_use_task fs128 user0:object_r:type0:s4:c5; fs_use_trans fs129 user0:object_r:type0:s4:c5; fs_use_xattr fs130 user0:object_r:type0:s4:c5; fs_use_task fs131 user0:object_r:type0:s4:c5; fs_use_trans fs132 user0:object_r:type0:s4:c5; fs_use_xattr fs133 user0:object_r:type0:s4:c5; fs_use_task fs134 user0:object_r:type0:s4:c5; fs_use_trans fs135 user0:object_r:type0:s4:c5; fs_use_xattr fs136 user0:object_r:type0:s4:c5; fs_use_task fs137 user0:object_r:type0:s4:c5; fs_use_trans fs138 user0:object_r:type0:s4:c5; fs_use_xattr fs139 user0:object_r:type0:s4:c5; fs_use_task fs140 user0:object_r:type0:s4:c5; fs_use_trans fs141 user0:object_r:type0:s4:c5; fs_use_xattr fs142 user0:object_r:type0:s4:c5; fs_use_task fs143 user0:object_r:type0:s4:c5; fs_use_trans fs144 user0:object_r:type0:s4:c5; fs_use_xattr fs145 user0:object_r:type0:s4:c5; fs_use_task fs146 user0:object_r:type0:s4:c5; fs_use_trans fs147 user0:object_r:type0:s4:c5; fs_use_xattr fs148 user0:object_r:type0:s4:c5; # 151 genfscon genfscon fs149 / user0:object_r:type0:s3 genfscon fs150 / user0:object_r:type0:s3 genfscon fs151 / user0:object_r:type0:s3 genfscon fs152 / user0:object_r:type0:s3 genfscon fs153 / user0:object_r:type0:s3 genfscon fs154 / user0:object_r:type0:s3 genfscon fs155 / user0:object_r:type0:s3 genfscon fs156 / user0:object_r:type0:s3 genfscon fs157 / user0:object_r:type0:s3 genfscon fs158 / user0:object_r:type0:s3 genfscon fs159 / user0:object_r:type0:s3 genfscon fs160 / user0:object_r:type0:s3 genfscon fs161 / user0:object_r:type0:s3 genfscon fs162 / user0:object_r:type0:s3 genfscon fs163 / user0:object_r:type0:s3 genfscon fs164 / user0:object_r:type0:s3 genfscon fs165 / user0:object_r:type0:s3 genfscon fs166 / user0:object_r:type0:s3 genfscon fs167 / user0:object_r:type0:s3 genfscon fs168 / user0:object_r:type0:s3 genfscon fs169 / user0:object_r:type0:s3 genfscon fs170 / user0:object_r:type0:s3 genfscon fs171 / user0:object_r:type0:s3 genfscon fs172 / user0:object_r:type0:s3 genfscon fs173 / user0:object_r:type0:s3 genfscon fs174 / user0:object_r:type0:s3 genfscon fs175 / user0:object_r:type0:s3 genfscon fs176 / user0:object_r:type0:s3 genfscon fs177 / user0:object_r:type0:s3 genfscon fs178 / user0:object_r:type0:s3 genfscon fs179 / user0:object_r:type0:s3 genfscon fs180 / user0:object_r:type0:s3 genfscon fs181 / user0:object_r:type0:s3 genfscon fs182 / user0:object_r:type0:s3 genfscon fs183 / user0:object_r:type0:s3 genfscon fs184 / user0:object_r:type0:s3 genfscon fs185 / user0:object_r:type0:s3 genfscon fs186 / user0:object_r:type0:s3 genfscon fs187 / user0:object_r:type0:s3 genfscon fs188 / user0:object_r:type0:s3 genfscon fs189 / user0:object_r:type0:s3 genfscon fs190 / user0:object_r:type0:s3 genfscon fs191 / user0:object_r:type0:s3 genfscon fs192 / user0:object_r:type0:s3 genfscon fs193 / user0:object_r:type0:s3 genfscon fs194 / user0:object_r:type0:s3 genfscon fs195 / user0:object_r:type0:s3 genfscon fs196 / user0:object_r:type0:s3 genfscon fs197 / user0:object_r:type0:s3 genfscon fs198 / user0:object_r:type0:s3 genfscon fs199 / user0:object_r:type0:s3 genfscon fs200 / user0:object_r:type0:s3 genfscon fs201 / user0:object_r:type0:s3 genfscon fs202 / user0:object_r:type0:s3 genfscon fs203 / user0:object_r:type0:s3 genfscon fs204 / user0:object_r:type0:s3 genfscon fs205 / user0:object_r:type0:s3 genfscon fs206 / user0:object_r:type0:s3 genfscon fs207 / user0:object_r:type0:s3 genfscon fs208 / user0:object_r:type0:s3 genfscon fs209 / user0:object_r:type0:s3 genfscon fs210 / user0:object_r:type0:s3 genfscon fs211 / user0:object_r:type0:s3 genfscon fs212 / user0:object_r:type0:s3 genfscon fs213 / user0:object_r:type0:s3 genfscon fs214 / user0:object_r:type0:s3 genfscon fs215 / user0:object_r:type0:s3 genfscon fs216 / user0:object_r:type0:s3 genfscon fs217 / user0:object_r:type0:s3 genfscon fs218 / user0:object_r:type0:s3 genfscon fs219 / user0:object_r:type0:s3 genfscon fs220 / user0:object_r:type0:s3 genfscon fs221 / user0:object_r:type0:s3 genfscon fs222 / user0:object_r:type0:s3 genfscon fs223 / user0:object_r:type0:s3 genfscon fs224 / user0:object_r:type0:s3 genfscon fs225 / user0:object_r:type0:s3 genfscon fs226 / user0:object_r:type0:s3 genfscon fs227 / user0:object_r:type0:s3 genfscon fs228 / user0:object_r:type0:s3 genfscon fs229 / user0:object_r:type0:s3 genfscon fs230 / user0:object_r:type0:s3 genfscon fs231 / user0:object_r:type0:s3 genfscon fs232 / user0:object_r:type0:s3 genfscon fs233 / user0:object_r:type0:s3 genfscon fs234 / user0:object_r:type0:s3 genfscon fs235 / user0:object_r:type0:s3 genfscon fs236 / user0:object_r:type0:s3 genfscon fs237 / user0:object_r:type0:s3 genfscon fs238 / user0:object_r:type0:s3 genfscon fs239 / user0:object_r:type0:s3 genfscon fs240 / user0:object_r:type0:s3 genfscon fs241 / user0:object_r:type0:s3 genfscon fs242 / user0:object_r:type0:s3 genfscon fs243 / user0:object_r:type0:s3 genfscon fs244 / user0:object_r:type0:s3 genfscon fs245 / user0:object_r:type0:s3 genfscon fs246 / user0:object_r:type0:s3 genfscon fs247 / user0:object_r:type0:s3 genfscon fs248 / user0:object_r:type0:s3 genfscon fs249 / user0:object_r:type0:s3 genfscon fs250 / user0:object_r:type0:s3 genfscon fs251 / user0:object_r:type0:s3 genfscon fs252 / user0:object_r:type0:s3 genfscon fs253 / user0:object_r:type0:s3 genfscon fs254 / user0:object_r:type0:s3 genfscon fs255 / user0:object_r:type0:s3 genfscon fs256 / user0:object_r:type0:s3 genfscon fs257 / user0:object_r:type0:s3 genfscon fs258 / user0:object_r:type0:s3 genfscon fs259 / user0:object_r:type0:s3 genfscon fs260 / user0:object_r:type0:s3 genfscon fs261 / user0:object_r:type0:s3 genfscon fs262 / user0:object_r:type0:s3 genfscon fs263 / user0:object_r:type0:s3 genfscon fs264 / user0:object_r:type0:s3 genfscon fs265 / user0:object_r:type0:s3 genfscon fs266 / user0:object_r:type0:s3 genfscon fs267 / user0:object_r:type0:s3 genfscon fs268 / user0:object_r:type0:s3 genfscon fs269 / user0:object_r:type0:s3 genfscon fs270 / user0:object_r:type0:s3 genfscon fs271 / user0:object_r:type0:s3 genfscon fs272 / user0:object_r:type0:s3 genfscon fs273 / user0:object_r:type0:s3 genfscon fs274 / user0:object_r:type0:s3 genfscon fs275 / user0:object_r:type0:s3 genfscon fs276 / user0:object_r:type0:s3 genfscon fs277 / user0:object_r:type0:s3 genfscon fs278 / user0:object_r:type0:s3 genfscon fs279 / user0:object_r:type0:s3 genfscon fs280 / user0:object_r:type0:s3 genfscon fs281 / user0:object_r:type0:s3 genfscon fs282 / user0:object_r:type0:s3 genfscon fs283 / user0:object_r:type0:s3 genfscon fs284 / user0:object_r:type0:s3 genfscon fs285 / user0:object_r:type0:s3 genfscon fs286 / user0:object_r:type0:s3 genfscon fs287 / user0:object_r:type0:s3 genfscon fs288 / user0:object_r:type0:s3 genfscon fs289 / user0:object_r:type0:s3 genfscon fs290 / user0:object_r:type0:s3 genfscon fs291 / user0:object_r:type0:s3 genfscon fs292 / user0:object_r:type0:s3 genfscon fs293 / user0:object_r:type0:s3 genfscon fs294 / user0:object_r:type0:s3 genfscon fs295 / user0:object_r:type0:s3 genfscon fs296 / user0:object_r:type0:s3 genfscon fs297 / user0:object_r:type0:s3 genfscon fs298 / user0:object_r:type0:s3 genfscon fs299 / user0:object_r:type0:s3 #163 portcons portcon tcp 2 user0:object_r:type0:s4:c5 portcon tcp 4 user0:object_r:type0:s4:c5 portcon tcp 6 user0:object_r:type0:s4:c5 portcon tcp 8 user0:object_r:type0:s4:c5 portcon tcp 10 user0:object_r:type0:s4:c5 portcon tcp 12 user0:object_r:type0:s4:c5 portcon tcp 14 user0:object_r:type0:s4:c5 portcon tcp 16 user0:object_r:type0:s4:c5 portcon tcp 18 user0:object_r:type0:s4:c5 portcon tcp 20 user0:object_r:type0:s4:c5 portcon tcp 22 user0:object_r:type0:s4:c5 portcon tcp 24 user0:object_r:type0:s4:c5 portcon tcp 26 user0:object_r:type0:s4:c5 portcon tcp 28 user0:object_r:type0:s4:c5 portcon tcp 30 user0:object_r:type0:s4:c5 portcon tcp 32 user0:object_r:type0:s4:c5 portcon tcp 34 user0:object_r:type0:s4:c5 portcon tcp 36 user0:object_r:type0:s4:c5 portcon tcp 38 user0:object_r:type0:s4:c5 portcon tcp 40 user0:object_r:type0:s4:c5 portcon tcp 42 user0:object_r:type0:s4:c5 portcon tcp 44 user0:object_r:type0:s4:c5 portcon tcp 46 user0:object_r:type0:s4:c5 portcon tcp 48 user0:object_r:type0:s4:c5 portcon tcp 50 user0:object_r:type0:s4:c5 portcon tcp 52 user0:object_r:type0:s4:c5 portcon tcp 54 user0:object_r:type0:s4:c5 portcon tcp 56 user0:object_r:type0:s4:c5 portcon tcp 58 user0:object_r:type0:s4:c5 portcon tcp 60 user0:object_r:type0:s4:c5 portcon tcp 62 user0:object_r:type0:s4:c5 portcon tcp 64 user0:object_r:type0:s4:c5 portcon tcp 66 user0:object_r:type0:s4:c5 portcon tcp 68 user0:object_r:type0:s4:c5 portcon tcp 70 user0:object_r:type0:s4:c5 portcon tcp 72 user0:object_r:type0:s4:c5 portcon tcp 74 user0:object_r:type0:s4:c5 portcon tcp 76 user0:object_r:type0:s4:c5 portcon tcp 78 user0:object_r:type0:s4:c5 portcon tcp 80 user0:object_r:type0:s4:c5 portcon tcp 82 user0:object_r:type0:s4:c5 portcon tcp 84 user0:object_r:type0:s4:c5 portcon tcp 86 user0:object_r:type0:s4:c5 portcon tcp 88 user0:object_r:type0:s4:c5 portcon tcp 90 user0:object_r:type0:s4:c5 portcon tcp 92 user0:object_r:type0:s4:c5 portcon tcp 94 user0:object_r:type0:s4:c5 portcon tcp 96 user0:object_r:type0:s4:c5 portcon tcp 98 user0:object_r:type0:s4:c5 portcon tcp 100 user0:object_r:type0:s4:c5 portcon tcp 102 user0:object_r:type0:s4:c5 portcon tcp 104 user0:object_r:type0:s4:c5 portcon tcp 106 user0:object_r:type0:s4:c5 portcon tcp 108 user0:object_r:type0:s4:c5 portcon tcp 110 user0:object_r:type0:s4:c5 portcon tcp 112 user0:object_r:type0:s4:c5 portcon tcp 114 user0:object_r:type0:s4:c5 portcon tcp 116 user0:object_r:type0:s4:c5 portcon tcp 118 user0:object_r:type0:s4:c5 portcon tcp 120 user0:object_r:type0:s4:c5 portcon tcp 122 user0:object_r:type0:s4:c5 portcon tcp 124 user0:object_r:type0:s4:c5 portcon tcp 126 user0:object_r:type0:s4:c5 portcon tcp 128 user0:object_r:type0:s4:c5 portcon tcp 130 user0:object_r:type0:s4:c5 portcon tcp 132 user0:object_r:type0:s4:c5 portcon tcp 134 user0:object_r:type0:s4:c5 portcon tcp 136 user0:object_r:type0:s4:c5 portcon tcp 138 user0:object_r:type0:s4:c5 portcon tcp 140 user0:object_r:type0:s4:c5 portcon tcp 142 user0:object_r:type0:s4:c5 portcon tcp 144 user0:object_r:type0:s4:c5 portcon tcp 146 user0:object_r:type0:s4:c5 portcon tcp 148 user0:object_r:type0:s4:c5 portcon tcp 150 user0:object_r:type0:s4:c5 portcon tcp 152 user0:object_r:type0:s4:c5 portcon tcp 154 user0:object_r:type0:s4:c5 portcon tcp 156 user0:object_r:type0:s4:c5 portcon tcp 158 user0:object_r:type0:s4:c5 portcon tcp 160 user0:object_r:type0:s4:c5 portcon tcp 162 user0:object_r:type0:s4:c5 portcon tcp 164 user0:object_r:type0:s4:c5 portcon tcp 166 user0:object_r:type0:s4:c5 portcon tcp 168 user0:object_r:type0:s4:c5 portcon tcp 170 user0:object_r:type0:s4:c5 portcon tcp 172 user0:object_r:type0:s4:c5 portcon tcp 174 user0:object_r:type0:s4:c5 portcon tcp 176 user0:object_r:type0:s4:c5 portcon tcp 178 user0:object_r:type0:s4:c5 portcon tcp 180 user0:object_r:type0:s4:c5 portcon tcp 182 user0:object_r:type0:s4:c5 portcon tcp 184 user0:object_r:type0:s4:c5 portcon tcp 186 user0:object_r:type0:s4:c5 portcon tcp 188 user0:object_r:type0:s4:c5 portcon tcp 190 user0:object_r:type0:s4:c5 portcon tcp 192 user0:object_r:type0:s4:c5 portcon tcp 194 user0:object_r:type0:s4:c5 portcon tcp 196 user0:object_r:type0:s4:c5 portcon tcp 198 user0:object_r:type0:s4:c5 portcon tcp 200 user0:object_r:type0:s4:c5 portcon tcp 202 user0:object_r:type0:s4:c5 portcon tcp 204 user0:object_r:type0:s4:c5 portcon tcp 206 user0:object_r:type0:s4:c5 portcon tcp 208 user0:object_r:type0:s4:c5 portcon tcp 210 user0:object_r:type0:s4:c5 portcon tcp 212 user0:object_r:type0:s4:c5 portcon tcp 214 user0:object_r:type0:s4:c5 portcon tcp 216 user0:object_r:type0:s4:c5 portcon tcp 218 user0:object_r:type0:s4:c5 portcon tcp 220 user0:object_r:type0:s4:c5 portcon tcp 222 user0:object_r:type0:s4:c5 portcon tcp 224 user0:object_r:type0:s4:c5 portcon tcp 226 user0:object_r:type0:s4:c5 portcon tcp 228 user0:object_r:type0:s4:c5 portcon tcp 230 user0:object_r:type0:s4:c5 portcon tcp 232 user0:object_r:type0:s4:c5 portcon tcp 234 user0:object_r:type0:s4:c5 portcon tcp 236 user0:object_r:type0:s4:c5 portcon tcp 238 user0:object_r:type0:s4:c5 portcon tcp 240 user0:object_r:type0:s4:c5 portcon tcp 242 user0:object_r:type0:s4:c5 portcon tcp 244 user0:object_r:type0:s4:c5 portcon tcp 246 user0:object_r:type0:s4:c5 portcon tcp 248 user0:object_r:type0:s4:c5 portcon tcp 250 user0:object_r:type0:s4:c5 portcon tcp 252 user0:object_r:type0:s4:c5 portcon tcp 254 user0:object_r:type0:s4:c5 portcon tcp 256 user0:object_r:type0:s4:c5 portcon tcp 258 user0:object_r:type0:s4:c5 portcon tcp 260 user0:object_r:type0:s4:c5 portcon tcp 262 user0:object_r:type0:s4:c5 portcon tcp 264 user0:object_r:type0:s4:c5 portcon tcp 266 user0:object_r:type0:s4:c5 portcon tcp 268 user0:object_r:type0:s4:c5 portcon tcp 270 user0:object_r:type0:s4:c5 portcon tcp 272 user0:object_r:type0:s4:c5 portcon tcp 274 user0:object_r:type0:s4:c5 portcon tcp 276 user0:object_r:type0:s4:c5 portcon tcp 278 user0:object_r:type0:s4:c5 portcon tcp 280 user0:object_r:type0:s4:c5 portcon tcp 282 user0:object_r:type0:s4:c5 portcon tcp 284 user0:object_r:type0:s4:c5 portcon tcp 286 user0:object_r:type0:s4:c5 portcon tcp 288 user0:object_r:type0:s4:c5 portcon tcp 290 user0:object_r:type0:s4:c5 portcon tcp 292 user0:object_r:type0:s4:c5 portcon tcp 294 user0:object_r:type0:s4:c5 portcon tcp 296 user0:object_r:type0:s4:c5 portcon tcp 298 user0:object_r:type0:s4:c5 portcon tcp 300 user0:object_r:type0:s4:c5 portcon tcp 302 user0:object_r:type0:s4:c5 portcon tcp 304 user0:object_r:type0:s4:c5 portcon tcp 306 user0:object_r:type0:s4:c5 portcon tcp 308 user0:object_r:type0:s4:c5 portcon tcp 310 user0:object_r:type0:s4:c5 portcon tcp 312 user0:object_r:type0:s4:c5 portcon tcp 314 user0:object_r:type0:s4:c5 portcon tcp 316 user0:object_r:type0:s4:c5 portcon tcp 318 user0:object_r:type0:s4:c5 portcon tcp 320 user0:object_r:type0:s4:c5 portcon tcp 322 user0:object_r:type0:s4:c5 portcon tcp 324 user0:object_r:type0:s4:c5 portcon tcp 326 user0:object_r:type0:s4:c5 #167 netifcon netifcon eth0 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth1 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth2 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth3 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth4 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth5 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth6 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth7 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth8 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth9 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth10 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth11 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth12 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth13 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth14 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth15 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth16 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth17 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth18 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth19 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth20 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth21 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth22 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth23 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth24 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth25 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth26 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth27 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth28 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth29 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth30 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth31 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth32 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth33 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth34 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth35 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth36 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth37 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth38 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth39 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth40 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth41 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth42 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth43 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth44 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth45 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth46 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth47 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth48 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth49 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth50 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth51 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth52 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth53 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth54 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth55 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth56 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth57 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth58 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth59 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth60 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth61 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth62 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth63 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth64 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth65 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth66 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth67 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth68 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth69 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth70 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth71 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth72 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth73 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth74 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth75 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth76 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth77 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth78 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth79 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth80 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth81 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth82 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth83 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth84 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth85 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth86 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth87 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth88 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth89 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth90 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth91 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth92 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth93 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth94 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth95 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth96 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth97 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth98 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth99 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth100 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth101 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth102 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth103 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth104 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth105 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth106 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth107 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth108 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth109 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth110 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth111 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth112 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth113 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth114 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth115 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth116 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth117 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth118 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth119 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth120 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth121 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth122 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth123 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth124 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth125 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth126 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth127 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth128 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth129 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth130 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth131 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth132 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth133 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth134 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth135 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth136 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth137 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth138 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth139 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth140 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth141 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth142 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth143 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth144 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth145 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth146 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth147 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth148 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth149 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth150 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth151 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth152 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth153 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth154 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth155 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth156 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth157 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth158 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth159 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth160 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth161 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth162 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth163 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth164 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth165 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 netifcon eth166 user0:object_r:type0:s4:c5 user0:object_r:type0:s4:c5 # 173 nodecons nodecon 127.0.0.0 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.1 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.2 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.3 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.4 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.5 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.6 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.7 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.8 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.9 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.10 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.11 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.12 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.13 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.14 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.15 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.16 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.17 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.18 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.19 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.20 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.21 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.22 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.23 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.24 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.25 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.26 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.27 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.28 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.29 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.30 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.31 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.32 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.33 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.34 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.35 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.36 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.37 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.38 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.39 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.40 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.41 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.42 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.43 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.44 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.45 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.46 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.47 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.48 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.49 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.50 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.51 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.52 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.53 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.54 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.55 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.56 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.57 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.58 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.59 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.60 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.61 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.62 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.63 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.64 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.65 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.66 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.67 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.68 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.69 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.70 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.71 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.72 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.73 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.74 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.75 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.76 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.77 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.78 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.79 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.80 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.81 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.82 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.83 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.84 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.85 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.86 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.87 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.88 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.89 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.90 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.91 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.92 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.93 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.94 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.95 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.96 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.97 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.98 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.99 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.100 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.101 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.102 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.103 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.104 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.105 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.106 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.107 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.108 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.109 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.110 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.111 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.112 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.113 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.114 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.115 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.116 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.117 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.118 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.119 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.120 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.121 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.122 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.123 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.124 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.125 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.126 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.127 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.128 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.129 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.130 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.131 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.132 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.133 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.134 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.135 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.136 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.137 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.138 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.139 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.140 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.141 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.142 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.143 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.144 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.145 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.146 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.147 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.148 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.149 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.150 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.151 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.152 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.153 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.154 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.155 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.156 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.157 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.158 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.159 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.160 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.161 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.162 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.163 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.164 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.165 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.166 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.167 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.168 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.169 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.170 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.171 255.255.255.255 user0:object_r:type0:s4:c5 nodecon 127.0.0.172 255.255.255.255 user0:object_r:type0:s4:c5 setools-4.4.0/tests/policyrep/selinuxpolicy.py000066400000000000000000000210011402045477700216440ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import copy import os import sys import unittest from setools import SELinuxPolicy, HandleUnknown from setools.exception import InvalidPolicy from .util import compile_policy class SELinuxPolicyTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/policyrep/selinuxpolicy.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) @unittest.skip("Retired for the SELinuxPolicyLoadError test suite.") def test_001_open_policy_error(self): """SELinuxPolicy: Invalid policy on open.""" # source policies not supported self.assertRaises(InvalidPolicy, SELinuxPolicy, "tests/policyrep/selinuxpolicy-bad.conf") def test_002_open_policy_non_existant(self): """SELinuxPolicy: Non existant policy on open.""" self.assertRaises(OSError, SELinuxPolicy, "tests/policyrep/DOES_NOT_EXIST") def test_003_deepcopy(self): """SELinuxPolicy: Deep copy""" p = copy.deepcopy(self.p) self.assertIs(self.p, p) def test_010_handle_unknown(self): """SELinuxPolicy: handle unknown setting.""" self.assertEqual(self.p.handle_unknown, HandleUnknown.reject) def test_011_mls(self): """SELinuxPolicy: MLS status.""" self.assertTrue(self.p.mls) def test_012_version(self): """SELinuxPolicy: version.""" self.assertTrue(self.p.version) def test_100_allow_count(self): """SELinuxPolicy: allow count""" self.assertEqual(self.p.allow_count, 113) def test_101_auditallow_count(self): """SELinuxPolicy: auditallow count""" self.assertEqual(self.p.auditallow_count, 109) def test_102_boolean_count(self): """SELinuxPolicy: Boolean count.""" self.assertEqual(self.p.boolean_count, 127) # def test_103_bounds_count(self): def test_104_category_count(self): """SELinuxPolicy: category count""" self.assertEqual(self.p.category_count, 17) def test_105_class_count(self): """SELinuxPolicy: object class count""" self.assertEqual(self.p.class_count, 7) def test_106_common_count(self): """SELinuxPolicy: common permisison set count""" self.assertEqual(self.p.common_count, 3) def test_107_conditional_count(self): """SELinuxPolicy: conditional (expression) count""" self.assertEqual(self.p.conditional_count, 67) def test_108_constraint_count(self): """SELinuxPolicy: standard constraint count""" self.assertEqual(self.p.constraint_count, 19) # def test_109_default_count(self): def test_110_dontaudit_count(self): """SELinuxPolicy: dontaudit rule count""" self.assertEqual(self.p.dontaudit_count, 107) def test_111_fs_use_count(self): """SELinuxPolicy: fs_use_* count""" self.assertEqual(self.p.fs_use_count, 149) def test_112_genfscon_count(self): """SELinuxPolicy: genfscon count""" self.assertEqual(self.p.genfscon_count, 151) def test_113_initial_sid_count(self): """SELinuxPolicy: initial sid count""" self.assertEqual(self.p.initialsids_count, 11) def test_114_level_count(self): """SELinuxPolicy: MLS level count""" self.assertEqual(self.p.level_count, 13) def test_115_mls_constraint_count(self): """SELinuxPolicy: MLS constraint count""" self.assertEqual(self.p.mlsconstraint_count, 23) def test_116_mls_validatetrans_count(self): """SELinuxPolicy: MLS validatetrans count""" self.assertEqual(self.p.mlsvalidatetrans_count, 3) def test_117_netifcon_count(self): """SELinuxPolicy: netifcon count""" self.assertEqual(self.p.netifcon_count, 167) def test_118_neverallow_count(self): """SELinuxPolicy: neverallow rule count""" # changed after dropping source policy support # self.assertEqual(self.p.neverallow_count, 103) self.assertEqual(self.p.neverallow_count, 0) def test_119_nodecon_count(self): """SELinuxPolicy: nodecon count""" self.assertEqual(self.p.nodecon_count, 173) def test_120_permission_count(self): """SELinuxPolicy: permission count""" self.assertEqual(self.p.permission_count, 29) def test_121_permissive_types_count(self): """SELinuxPolicy: permissive types count""" self.assertEqual(self.p.permissives_count, 73) def test_122_polcap_count(self): """SELinuxPolicy: policy capability count""" self.assertEqual(self.p.polcap_count, 2) def test_123_portcon_count(self): """SELinuxPolicy: portcon count""" self.assertEqual(self.p.portcon_count, 163) def test_124_range_transition_count(self): """SELinuxPolicy: range_transition count""" self.assertEqual(self.p.range_transition_count, 71) def test_125_role_count(self): """SELinuxPolicy: role count""" self.assertEqual(self.p.role_count, 131) # def test_126_role_attribute_count(self): def test_127_role_allow_count(self): """SELinuxPolicy: (role) allow count""" self.assertEqual(self.p.role_allow_count, 83) def test_128_role_transition_count(self): """SELinuxPolicy: role_transition count""" self.assertEqual(self.p.role_transition_count, 79) def test_129_type_count(self): """SELinuxPolicy: type count""" self.assertEqual(self.p.type_count, 137) def test_130_type_attribute_count(self): """SELinuxPolicy: type attribute count""" self.assertEqual(self.p.type_attribute_count, 157) def test_131_type_change_count(self): """SELinuxPolicy: type_change rule count""" self.assertEqual(self.p.type_change_count, 89) def test_132_type_member_count(self): """SELinuxPolicy: type_member rule count""" self.assertEqual(self.p.type_member_count, 61) def test_133_type_transition_count(self): """SELinuxPolicy: type_transition rule count""" self.assertEqual(self.p.type_transition_count, 97) def test_134_user_count(self): """SELinuxPolicy: user count""" self.assertEqual(self.p.user_count, 101) def test_135_validatetrans_count(self): """SELinuxPolicy: validatetrans count""" self.assertEqual(self.p.validatetrans_count, 5) def test_136_allowxperm_count(self): """SELinuxPolicy: allowxperm rount""" self.assertEqual(self.p.allowxperm_count, 179) def test_137_allowxperm_count(self): """SELinuxPolicy: auditallowxperm rount""" self.assertEqual(self.p.auditallowxperm_count, 181) def test_138_neverallowxperm_count(self): """SELinuxPolicy: neverallowxperm rount""" # changed after dropping source policy support # self.assertEqual(self.p.neverallowxperm_count, 191) self.assertEqual(self.p.neverallowxperm_count, 0) def test_139_allowxperm_count(self): """SELinuxPolicy: dontauditxperm rount""" self.assertEqual(self.p.dontauditxperm_count, 193) @unittest.skip("No longer necessary since source policy support was dropped.") class SELinuxPolicyLoadError(unittest.TestCase): """Test attempted loading of non-compiling policies.""" def _load_policy(self, policy): self.assertRaises(InvalidPolicy, SELinuxPolicy, "tests/policyrep/invalid_policies/" + policy) def test_nodecon_invalid_range(self): """SELinuxPolicy: invalid nodecon range (category not associated) error.""" self._load_policy("nodecon-invalid-range.conf") sys.stderr.write("The \"category can not be associated\" error above is expected.") # this is not fixed yet. See issue #72 @unittest.expectedFailure def test_user_level_not_in_range(self): """SELinuxPolicy: error for user's default level isn't within the range.""" self._load_policy("user-level-not-in-range.conf") setools-4.4.0/tests/policyrep/symbol.py000066400000000000000000000060761402045477700202610ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import copy import unittest from unittest.mock import Mock, patch from setools import SELinuxPolicy @unittest.skip("Needs to be reworked for cython") class PolicySymbolTest(unittest.TestCase): """Tests for base symbol class methods.""" def mock_symbol_factory(self, name): """Factory function for Role objects, using a mock qpol object.""" mock_role = Mock(qpol.qpol_role_t) mock_role.name.return_value = name mock_role.this = name mock_policy = Mock(qpol.qpol_policy_t) return PolicySymbol(mock_policy, mock_role) def test_001_string(self): """Symbol: string representation""" sym = self.mock_symbol_factory("test1") self.assertEqual("test1", str(sym)) def test_010_hash(self): """Symbol: hash""" sym = self.mock_symbol_factory("test10") self.assertEqual(hash("test10"), hash(sym)) def test_020_eq(self): """Symbol: equality""" sym1 = self.mock_symbol_factory("test20") sym2 = self.mock_symbol_factory("test20") self.assertEqual(sym1, sym2) def test_021_eq(self): """Symbol: equality with string""" sym = self.mock_symbol_factory("test21") self.assertEqual("test21", sym) def test_030_ne(self): """Symbol: inequality""" sym1 = self.mock_symbol_factory("test30a") sym2 = self.mock_symbol_factory("test30b") self.assertNotEqual(sym1, sym2) def test_031_ne(self): """Symbol: inequality with string""" sym = self.mock_symbol_factory("test31a") self.assertNotEqual("test31b", sym) def test_040_lt(self): """Symbol: less-than""" sym1 = self.mock_symbol_factory("test40a") sym2 = self.mock_symbol_factory("test40b") self.assertTrue(sym1 < sym2) sym1 = self.mock_symbol_factory("test40") sym2 = self.mock_symbol_factory("test40") self.assertFalse(sym1 < sym2) sym1 = self.mock_symbol_factory("test40b") sym2 = self.mock_symbol_factory("test40a") self.assertFalse(sym1 < sym2) def test_050_deepcopy(self): """Symbol: deep copy""" sym1 = self.mock_symbol_factory("test50") sym2 = copy.deepcopy(sym1) self.assertIs(sym1.policy, sym2.policy) self.assertIs(sym1.qpol_symbol, sym2.qpol_symbol) setools-4.4.0/tests/policyrep/terule.py000066400000000000000000000404201402045477700202430ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable import unittest from unittest.mock import Mock, patch from setools import SELinuxPolicy from setools.exception import InvalidTERuleType, RuleNotConditional, RuleUseError, \ TERuleNoFilename @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class AVRuleTest(unittest.TestCase): def mock_avrule_factory(self, ruletype, source, target, tclass, perms, cond=None): mock_rule = Mock(qpol_avrule_t) mock_rule.is_extended.return_value = False mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.perm_iter = lambda x: iter(perms) if cond: mock_rule.cond.return_value = cond else: # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """AVRule factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """AVRule valid rule types.""" for r in ["allow", "neverallow", "auditallow", "dontaudit"]: self.assertEqual(r, validate_ruletype(r)) def test_002_validate_ruletype_invalid(self): """AVRule valid rule types.""" with self.assertRaises(InvalidTERuleType): self.assertTrue(validate_ruletype("role_transition")) def test_010_ruletype(self): """AVRule rule type""" rule = self.mock_avrule_factory("neverallow", "a", "b", "c", ['d']) self.assertEqual(TERuletype.neverallow, rule.ruletype) def test_020_source_type(self): """AVRule source type""" rule = self.mock_avrule_factory("allow", "source20", "b", "c", ['d']) self.assertEqual("source20", rule.source) def test_030_target_type(self): """AVRule target type""" rule = self.mock_avrule_factory("allow", "a", "target30", "c", ['d']) self.assertEqual("target30", rule.target) def test_040_object_class(self): """AVRule object class""" rule = self.mock_avrule_factory("allow", "a", "b", "class40", ['d']) self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """AVRule permissions""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['perm50a', 'perm50b']) self.assertSetEqual(set(['perm50a', 'perm50b']), rule.perms) def test_060_conditional(self): """AVRule conditional expression""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d'], cond="cond60") self.assertEqual("cond60", rule.conditional) def test_061_unconditional(self): """AVRule conditional expression (none)""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """AVRule default type""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleUseError): rule.default def test_080_filename(self): """AVRule filename (none)""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) with self.assertRaises(RuleUseError): rule.filename def test_100_statement_one_perm(self): """AVRule statement, one permission.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d']) self.assertEqual("allow a b:c d;", rule.statement()) def test_101_statement_two_perms(self): """AVRule statement, two permissions.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d1', 'd2']) # permissions are stored in a set, so the order may vary self.assertRegex(rule.statement(), "(" "allow a b:c { d1 d2 };" "|" "allow a b:c { d2 d1 };" ")") def test_102_statement_one_perm_cond(self): """AVRule statement, one permission, conditional.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d'], cond="cond102") self.assertEqual("allow a b:c d; [ cond102 ]:True", rule.statement()) def test_103_statement_two_perms_cond(self): """AVRule statement, two permissions, conditional.""" rule = self.mock_avrule_factory("allow", "a", "b", "c", ['d1', 'd2'], cond="cond103") # permissions are stored in a set, so the order may vary self.assertRegex(rule.statement(), "(" "allow a b:c { d1 d2 }; \[ cond103 ]" # noqa "|" "allow a b:c { d2 d1 }; \[ cond103 ]" ")") @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class AVRuleXpermTest(unittest.TestCase): def mock_avrule_factory(self, ruletype, source, target, tclass, xperm, perms): mock_rule = Mock(qpol_avrule_t) mock_rule.is_extended.return_value = True mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.xperm_type.return_value = xperm mock_rule.xperm_iter = lambda x: iter(perms) # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """AVRuleXperm factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """AVRuleXperm valid rule types.""" for r in ["allowxperm", "neverallowxperm", "auditallowxperm", "dontauditxperm"]: self.assertEqual(r, validate_ruletype(r)) def test_010_ruletype(self): """AVRuleXperm rule type""" rule = self.mock_avrule_factory("neverallowxperm", "a", "b", "c", "d", [0x0001]) self.assertEqual(TERuletype.neverallowxperm, rule.ruletype) def test_020_source_type(self): """AVRuleXperm source type""" rule = self.mock_avrule_factory("allowxperm", "source20", "b", "c", "d", [0x0001]) self.assertEqual("source20", rule.source) def test_030_target_type(self): """AVRuleXperm target type""" rule = self.mock_avrule_factory("allowxperm", "a", "target30", "c", "d", [0x0001]) self.assertEqual("target30", rule.target) def test_040_object_class(self): """AVRuleXperm object class""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "class40", "d", [0x0001]) self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """AVRuleXperm permissions""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0002, 0x0003]) self.assertSetEqual(set([0x0001, 0x0002, 0x0003]), rule.perms) def test_060_xperm_type(self): """AVRuleXperm xperm type""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "xperm60", [0x0001]) self.assertEqual("xperm60", rule.xperm_type) def test_070_unconditional(self): """AVRuleXperm conditional expression (none)""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleNotConditional): rule.conditional def test_080_default(self): """AVRuleXperm default type""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleUseError): rule.default def test_090_filename(self): """AVRuleXperm filename (none)""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) with self.assertRaises(RuleUseError): rule.filename def test_100_statement_one_perm(self): """AVRuleXperm statement, one permission.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001]) self.assertEqual("allowxperm a b:c d 0x0001;", rule.statement()) def test_101_statement_two_perms(self): """AVRuleXperm statement, two permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0003]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0001 0x0003 };") def test_102_statement_range_perms(self): """AVRuleXperm statement, range of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", list(range(0x0010, 0x0015))) self.assertEqual(rule.statement(), "allowxperm a b:c d 0x0010-0x0014;") def test_103_statement_single_perm_range_perms(self): """AVRuleXperm statement, single perm with range of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0001, 0x0003, 0x0004, 0x0005]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0001 0x0003-0x0005 };") def test_104_statement_two_range_perms(self): """AVRuleXperm statement, two ranges of permissions.""" rule = self.mock_avrule_factory("allowxperm", "a", "b", "c", "d", [0x0003, 0x0004, 0x0005, 0x0007, 0x0008, 0x0009]) self.assertEqual(rule.statement(), "allowxperm a b:c d { 0x0003-0x0005 0x0007-0x0009 };") @unittest.skip("Needs to be reworked for cython") @patch('setools.policyrep.boolcond.condexpr_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_factory', lambda x, y: y) @patch('setools.policyrep.typeattr.type_or_attr_factory', lambda x, y: y) @patch('setools.policyrep.objclass.class_factory', lambda x, y: y) class TERuleTest(unittest.TestCase): def mock_terule_factory(self, ruletype, source, target, tclass, default, cond=None, filename=None): if filename: assert not cond mock_rule = Mock(qpol_filename_trans_t) mock_rule.filename.return_value = filename else: mock_rule = Mock(qpol_terule_t) if cond: mock_rule.cond.return_value = cond else: # this actually comes out of condexpr_factory # but it's simpler to have here mock_rule.cond.side_effect = AttributeError mock_rule.rule_type.return_value = TERuletype.lookup(ruletype) mock_rule.source_type.return_value = source mock_rule.target_type.return_value = target mock_rule.object_class.return_value = tclass mock_rule.default_type.return_value = default return te_rule_factory(self.p, mock_rule) def setUp(self): self.p = Mock(qpol_policy_t) def test_000_factory(self): """TERule factory lookup.""" with self.assertRaises(TypeError): te_rule_factory(self.p, "INVALID") @unittest.skip("TE ruletype changed to an enumeration.") def test_001_validate_ruletype(self): """TERule valid rule types.""" for r in ["type_transition", "type_change", "type_member"]: self.assertEqual(r, validate_ruletype(r)) @unittest.skip("TE ruletype changed to an enumeration.") def test_002_validate_ruletype_invalid(self): """TERule valid rule types.""" with self.assertRaises(InvalidTERuleType): self.assertTrue(validate_ruletype("role_transition")) def test_010_ruletype(self): """TERule rule type""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") self.assertEqual(TERuletype.type_transition, rule.ruletype) def test_020_source_type(self): """TERule source type""" rule = self.mock_terule_factory("type_transition", "source20", "b", "c", "d") self.assertEqual("source20", rule.source) def test_030_target_type(self): """TERule target type""" rule = self.mock_terule_factory("type_transition", "a", "target30", "c", "d") self.assertEqual("target30", rule.target) def test_040_object_class(self): """TERule object class""" rule = self.mock_terule_factory("type_transition", "a", "b", "class40", "d") self.assertEqual("class40", rule.tclass) def test_050_permissions(self): """TERule permissions""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(RuleUseError): rule.perms def test_060_conditional(self): """TERule conditional expression""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", cond="cond60") self.assertEqual("cond60", rule.conditional) def test_061_unconditional(self): """TERule conditional expression (none)""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(RuleNotConditional): rule.conditional def test_070_default(self): """TERule default type""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "default70") self.assertEqual("default70", rule.default) def test_080_filename(self): """TERule filename""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", filename="name80") self.assertEqual("name80", rule.filename) def test_081_filename_none(self): """TERule filename (none)""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d") with self.assertRaises(TERuleNoFilename): rule.filename def test_082_filename_wrong_ruletype(self): """TERule filename on wrong ruletype""" rule = self.mock_terule_factory("type_change", "a", "b", "c", "d") with self.assertRaises(RuleUseError): rule.filename def test_100_statement(self): """TERule statement.""" rule1 = self.mock_terule_factory("type_transition", "a", "b", "c", "d") rule2 = self.mock_terule_factory("type_change", "a", "b", "c", "d") self.assertEqual("type_transition a b:c d;", rule1.statement()) self.assertEqual("type_change a b:c d;", rule2.statement()) def test_102_statement_cond(self): """TERule statement, conditional.""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", cond="cond102") self.assertEqual("type_transition a b:c d; [ cond102 ]:True", rule.statement()) def test_103_statement_filename(self): """TERule statement, two permissions, conditional.""" rule = self.mock_terule_factory("type_transition", "a", "b", "c", "d", filename="name103") self.assertEqual("type_transition a b:c d \"name103\";", rule.statement()) setools-4.4.0/tests/policyrep/typeattr.conf000066400000000000000000000046321402045477700211210ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } 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; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; attribute attr1; attribute attr2; attribute attr3; type system alias sysalias; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; type everything alias { alias1 alias2 }, attr1, attr2; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/typeattr.py000066400000000000000000000262161402045477700206260ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock, patch from setools import SELinuxPolicy from setools.exception import InvalidType, SymbolUseError @unittest.skip("Needs to be reworked for cython") class TypeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") def mock_type_factory(self, name, attrs=[], alias=[], perm=False): """Factory function for Type objects, using a mock qpol object.""" mock_type = Mock(qpol.qpol_type_t) mock_type.name.return_value = name mock_type.type_iter.side_effect = AssertionError("Type iterator used") mock_type.attr_iter = lambda x: iter(attrs) mock_type.alias_iter = lambda x: iter(alias) mock_type.ispermissive.return_value = perm mock_type.isattr.return_value = False mock_type.isalias.return_value = False return type_factory(self.p.policy, mock_type) def test_001_lookup(self): """Type factory policy lookup.""" type_ = type_factory(self.p.policy, "system") self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """Type factory policy invalid lookup.""" with self.assertRaises(InvalidType): type_factory(self.p.policy, "INVALID") def test_003_lookup_alias(self): """Type factory policy lookup alias.""" type_ = type_factory(self.p.policy, "sysalias", deref=True) self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_004_lookup_alias_no_deref(self): """Type factory policy lookup alias (no dereference).""" with self.assertRaises(TypeError): type_ = type_factory(self.p.policy, "sysalias") def test_005_lookup_attr(self): """Type factory policy lookup atribute.""" with self.assertRaises(TypeError): type_ = type_factory(self.p.policy, "attr1") def test_006_lookup2(self): """Type factory policy lookup (type_or_attr_factory).""" type_ = type_or_attr_factory(self.p.policy, "system") self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_007_lookup2_invalid(self): """Type factory policy invalid lookup (type_or_attr_factory).""" with self.assertRaises(InvalidType): type_or_attr_factory(self.p.policy, "INVALID") def test_008_lookup2_alias(self): """Type factory policy lookup alias (type_or_attr_factory).""" type_ = type_or_attr_factory(self.p.policy, "sysalias", deref=True) self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) def test_009_lookup2_alias_no_deref(self): """Type factory policy lookup alias (no dereference, type_or_attr_factory).""" with self.assertRaises(TypeError): type_ = type_or_attr_factory(self.p.policy, "sysalias") def test_00a_lookup_object(self): """Type factory policy lookup of Type object.""" type1 = type_factory(self.p.policy, "system") type2 = type_factory(self.p.policy, type1) self.assertIs(type2, type1) def test_00b_lookup2_object(self): """Type factory policy lookup of Type object (type_or_attr_factory).""" type1 = type_or_attr_factory(self.p.policy, "system") type2 = type_or_attr_factory(self.p.policy, type1) self.assertIs(type2, type1) def test_010_string(self): """Type basic string rendering.""" type_ = self.mock_type_factory("name10") self.assertEqual("name10", str(type_)) def test_020_attrs(self): """Type attributes""" type_ = self.mock_type_factory("name20", attrs=['attr1', 'attr2', 'attr3']) self.assertEqual(['attr1', 'attr2', 'attr3'], sorted(type_.attributes())) def test_030_aliases(self): """Type aliases""" type_ = self.mock_type_factory("name30", alias=['alias1', 'alias2', 'alias3']) self.assertEqual(['alias1', 'alias2', 'alias3'], sorted(type_.aliases())) def test_040_expand(self): """Type expansion""" type_ = self.mock_type_factory("name40") expanded = list(type_.expand()) self.assertEqual(1, len(expanded)) self.assertIs(type_, expanded[0]) def test_050_permissive(self): """Type is permissive""" type_ = self.mock_type_factory("name50a") permtype = self.mock_type_factory("name50b", perm=True) self.assertFalse(type_.ispermissive) self.assertTrue(permtype.ispermissive) def test_060_statement(self): """Type basic statement""" type_ = self.mock_type_factory("name60") self.assertEqual("type name60;", type_.statement()) def test_061_statement_one_attr(self): """Type statement, one attribute""" type_ = self.mock_type_factory("name61", attrs=['attr1']) self.assertEqual("type name61, attr1;", type_.statement()) def test_062_statement_two_attr(self): """Type statement, two attributes""" type_ = self.mock_type_factory("name62", attrs=['attr1', 'attr2']) self.assertEqual("type name62, attr1, attr2;", type_.statement()) def test_063_statement_one_alias(self): """Type statement, one alias""" type_ = self.mock_type_factory("name63", alias=['alias1']) self.assertEqual("type name63 alias alias1;", type_.statement()) def test_064_statement_two_alias(self): """Type statement, two aliases""" type_ = self.mock_type_factory("name64", alias=['alias1', 'alias2']) self.assertEqual("type name64 alias { alias1 alias2 };", type_.statement()) def test_065_statement_one_attr_one_alias(self): """Type statement, one attribute, one alias""" type_ = self.mock_type_factory("name65", attrs=['attr1'], alias=['alias1']) self.assertEqual("type name65 alias alias1, attr1;", type_.statement()) def test_066_statement_two_attr_one_alias(self): """Type statement, two attributes, one alias""" type_ = self.mock_type_factory("name66", attrs=['attr1', 'attr2'], alias=['alias1']) self.assertEqual("type name66 alias alias1, attr1, attr2;", type_.statement()) def test_067_statement_one_attr_two_alias(self): """Type statement, one attribute, two aliases""" type_ = self.mock_type_factory("name67", attrs=['attr2'], alias=['alias3', 'alias4']) self.assertEqual("type name67 alias { alias3 alias4 }, attr2;", type_.statement()) def test_068_statement_two_attr_two_alias(self): """Type statement, two attributes, two aliases""" type_ = self.mock_type_factory("name68", attrs=['attr2', 'attr3'], alias=['alias2', 'alias4']) self.assertEqual("type name68 alias { alias2 alias4 }, attr2, attr3;", type_.statement()) @unittest.skip("Needs to be reworked for cython") class TypeAttributeTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") def mock_attr_factory(self, name, types=[]): """Factory function for TypeAttribute objects, using a mock qpol object.""" mock_type = Mock(qpol.qpol_type_t) mock_type.name.return_value = name mock_type.type_iter = lambda x: iter(types) mock_type.attr_iter.side_effect = AssertionError("Attr iter used") mock_type.alias_iter.side_effect = AssertionError("Alias iter used") mock_type.ispermissive.side_effect = AssertionError("Permissive used") mock_type.isattr.return_value = True mock_type.isalias.side_effect = AssertionError("Alias used") return attribute_factory(self.p.policy, mock_type) def test_001_lookup(self): """TypeAttribute factory policy lookup.""" attr = attribute_factory(self.p.policy, "attr1") self.assertEqual("attr1", attr.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """TypeAttribute factory policy invalid lookup.""" with self.assertRaises(InvalidType): attribute_factory(self.p.policy, "INVALID") def test_006_lookup2(self): """TypeAttribute factory policy lookup (type_or_attr_factory).""" attr = type_or_attr_factory(self.p.policy, "attr1") self.assertEqual("attr1", attr.qpol_symbol.name(self.p.policy)) def test_007_lookup2_invalid(self): """TypeAttribute factory policy invalid lookup (type_or_attr_factory).""" with self.assertRaises(InvalidType): type_or_attr_factory(self.p.policy, "INVALID") def test_008_lookup_object(self): """TypeAttribute factory policy lookup of TypeAttribute object.""" attr1 = attribute_factory(self.p.policy, "attr1") attr2 = attribute_factory(self.p.policy, attr1) self.assertIs(attr2, attr1) def test_009_lookup2_object(self): """TypeAttribute factory policy lookup of TypeAttribute object (type_or_attr_factory).""" attr1 = type_or_attr_factory(self.p.policy, "attr2") attr2 = type_or_attr_factory(self.p.policy, attr1) self.assertIs(attr2, attr1) def test_010_string(self): """TypeAttribute basic string rendering.""" attr = self.mock_attr_factory("name10") self.assertEqual("name10", str(attr)) def test_020_attrs(self): """TypeAttribute attributes""" attr = self.mock_attr_factory("name20") with self.assertRaises(SymbolUseError): attr.attributes() def test_030_aliases(self): """TypeAttribute aliases""" attr = self.mock_attr_factory("name30") with self.assertRaises(SymbolUseError): attr.aliases() def test_040_expand(self): """TypeAttribute expansion""" attr = self.mock_attr_factory("name40", types=['type31a', 'type31b', 'type31c']) self.assertEqual(['type31a', 'type31b', 'type31c'], sorted(attr.expand())) def test_050_permissive(self): with self.assertRaises(SymbolUseError): attr = self.mock_attr_factory("name20") attr.ispermissive def test_060_statement(self): """TypeAttribute basic statement""" attr = self.mock_attr_factory("name60") self.assertEqual("attribute name60;", attr.statement()) def test_070_contains(self): """TypeAttribute: contains""" attr = self.mock_attr_factory("name70", types=['type31a', 'type31b', 'type31c']) self.assertIn("type31b", attr) self.assertNotIn("type30", attr) setools-4.4.0/tests/policyrep/user.conf000066400000000000000000000044401402045477700202200ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; dominance { s0 s1 s2 } 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; #level decl level s0:c0.c2; level s1:c0.c13; level s2:c0.c13; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 portcon tcp 1 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/policyrep/user.py000066400000000000000000000130401402045477700177170ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # Until this is fixed for cython: # pylint: disable=undefined-variable,no-member import unittest from unittest.mock import Mock, patch from setools import SELinuxPolicy from setools.exception import MLSDisabled, InvalidUser @unittest.skip("Needs to be reworked for cython") class UserTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = SELinuxPolicy("tests/policyrep/user.conf") def mock_user_factory(self, name, roles, level=None, range_=None): """Factory function for User objects, using a mock qpol object.""" assert (level and range_) or (not level and not range_) # inject object_r, like the compiler does roles_with_objr = roles roles_with_objr.append('object_r') mock_user = Mock(qpol.qpol_user_t) mock_user.name.return_value = name mock_user.role_iter = lambda x: iter(roles_with_objr) mock_user.dfltlevel.return_value = level mock_user.range.return_value = range_ return user_factory(self.p.policy, mock_user) def test_001_lookup(self): """User factory policy lookup.""" user = user_factory(self.p.policy, "user10") self.assertEqual("user10", user.qpol_symbol.name(self.p.policy)) def test_002_lookup_invalid(self): """User factory policy invalid lookup.""" with self.assertRaises(InvalidUser): user_factory(self.p.policy, "INVALID") def test_003_lookup_object(self): """User factory policy lookup of User object.""" user1 = user_factory(self.p.policy, "user10") user2 = user_factory(self.p.policy, user1) self.assertIs(user2, user1) def test_010_string(self): """User basic string rendering.""" user = self.mock_user_factory("username", ['role1']) self.assertEqual("username", str(user)) def test_020_statement_role(self): """User statement, one role.""" with patch('setools.policyrep.mls.enabled', return_value=False): user = self.mock_user_factory("username", ['role20_r']) self.assertEqual("user username roles role20_r;", user.statement()) def test_021_statement_two_roles(self): """User statement, two roles.""" with patch('setools.policyrep.mls.enabled', return_value=False): user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) # roles are stored in a set, so the role order may vary self.assertRegex(user.statement(), "(" "user username roles { role20_r role21a_r };" "|" "user username roles { role21a_r role20_r };" ")") def test_022_statement_one_role_mls(self): """User statement, one role, MLS.""" user = self.mock_user_factory("username", ['role20_r'], level="s0", range_="s0-s2") self.assertEqual("user username roles role20_r level s0 range s0 - s2;", user.statement()) def test_023_statement_two_roles_mls(self): """User statement, two roles, MLS.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0 - s2") # roles are stored in a set, so the role order may vary self.assertRegex( user.statement(), "(" "user username roles { role20_r role21a_r } level s0 range s0 - s2;" "|" "user username roles { role21a_r role20_r } level s0 range s0 - s2;" ")") def test_030_roles(self): """User roles.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) self.assertSetEqual(user.roles, set(['role20_r', 'role21a_r'])) def test_040_level(self): """User level.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") self.assertEqual("s0", user.mls_level) def test_041_level_non_mls(self): """User level, MLS disabled.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r']) with patch('setools.policyrep.mls.enabled', return_value=False): with self.assertRaises(MLSDisabled): user.mls_level def test_050_range(self): """User level.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") self.assertEqual("s0 - s2", user.mls_range) def test_051_range_non_mls(self): """User level, MLS disabled.""" user = self.mock_user_factory("username", ['role20_r', 'role21a_r'], level="s0", range_="s0-s2") with patch('setools.policyrep.mls.enabled', return_value=False): with self.assertRaises(MLSDisabled): user.mls_range setools-4.4.0/tests/policyrep/util.py000066400000000000000000000041671402045477700177300ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # Copyright 2018, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import subprocess import tempfile from setools import SELinuxPolicy def compile_policy(source_file, mls=True, xen=False): """ Compile the specified source policy. Checkpolicy is assumed to be /usr/bin/checkpolicy. Otherwise the path must be specified in the CHECKPOLICY environment variable. Return: A SELinuxPolicy object. """ # create a temp file for the binary policy # and then have checkpolicy overwrite it. fd, policy_path = tempfile.mkstemp() os.close(fd) if "USERSPACE_SRC" in os.environ: command = [os.environ['USERSPACE_SRC'] + "/checkpolicy/checkpolicy"] elif "CHECKPOLICY" in os.environ: command = [os.environ['CHECKPOLICY']] else: command = ["/usr/bin/checkpolicy"] if mls: command.append("-M") if xen: command.extend(["-t", "xen", "-c", "30"]) command.extend(["-o", policy_path, "-U", "reject", source_file]) with open(os.devnull, "w") as null: subprocess.check_call(command, stdout=null, shell=False, close_fds=True) try: policy = SELinuxPolicy(policy_path) except Exception: # This should never be hit, since this policy # successfully compiled with checkpolicy above. # If we do, clean up the binary policy since # tearDownClass() does not run. os.unlink(policy_path) raise return policy setools-4.4.0/tests/portconquery.conf000066400000000000000000000163441402045477700200140ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; #level decl level s0:c0.c4; level s1:c0.c4; level s2:c0.c4; level s3:c0.c4; level s4:c0.c4; level s5:c0.c4; level s6:c0.c4; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; role role20_r; role role21a_r; role role21b_r; role role21c_r; role role20_r types system; role role21a_r types system; role role21b_r types system; role role21c_r types system; type type30; type type31a; type type31b; type type31c; role system types { type30 type31a type31b type31c }; allow system self:infoflow hi_w; #users user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s6:c0.c4; user user10 roles system level s0 range s0 - s2:c0.c4; user user11a roles system level s0 range s0 - s2:c0.c4; user user11b roles system level s0 range s0 - s2:c0.c4; user user11c roles system level s0 range s0 - s2:c0.c4; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0 sid security system:system:system:s0 #fs_use fs_use_trans devpts system:object_r:system:s0; fs_use_xattr ext3 system:object_r:system:s0; fs_use_task pipefs system:object_r:system:s0; #genfscon genfscon proc / system:object_r:system:s1 genfscon proc /sys system:object_r:system:s0 genfscon selinuxfs / system:object_r:system:s2:c0.c4 # test 1: # protocol: UDP # ports: unset # user: unset # role: unset # type: unset # range: unset portcon udp 1 system:system:system:s0:c0.c1 # test 10: # protocol: unset # ports: unset # user: user10, exact # role: unset # type: unset # range: unset portcon tcp 10 user10:system:system:s0:c0.c1 # test 11: # protocol: unset # ports: unset # user: user11(a|b), regex # role: unset # type: unset # range: unset portcon tcp 11 user11a:system:system:s0:c0.c1 portcon tcp 11000 user11b:system:system:s0:c0.c1 portcon tcp 11001 user11c:system:system:s0:c0.c1 # test 20: # protocol: unset # ports: unset # user: unset # role: role20_r, exact # type: unset # range: unset portcon tcp 20 system:role20_r:system:s0:c0.c1 # test 21: # protocol: unset # ports: unset # user: unset # role: role20(a|c)_r, regex # type: unset # range: unset portcon tcp 21 system:role21a_r:system:s0:c0.c1 portcon tcp 21000 system:role21b_r:system:s0:c0.c1 portcon tcp 21001 system:role21c_r:system:s0:c0.c1 # test 30: # protocol: unset # ports: unset # user: unset # role: unset # type: type30 # range: unset portcon tcp 30 system:system:type30:s0:c0.c1 # test 31: # protocol: unset # ports: unset # user: unset # role: unset # type: type31(b|c) # range: unset portcon tcp 31 system:system:type31a:s0:c0.c1 portcon tcp 31000 system:system:type31b:s0:c0.c1 portcon tcp 31001 system:system:type31c:s0:c0.c1 # test 40: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: equal portcon tcp 40 system:system:system:s0:c1 - s0:c0.c4 # test 41: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: overlap portcon tcp 41 system:system:system:s1:c1 - s1:c1.c3 # test 42: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: subset portcon tcp 42 system:system:system:s2:c1 - s2:c1.c3 # test 43: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: superset portcon tcp 43 system:system:system:s3:c1 - s3:c1.c3 # test 44: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: proper subset portcon tcp 44 system:system:system:s4:c1 - s4:c1.c3 # test 45: # protocol: unset # ports: unset # user: unset # role: unset # type: unset # range: proper superset portcon tcp 45 system:system:system:s5:c1 - s5:c1.c3 # test 50: # protocol: unset # ports: (50, 50) # user: unset # role: unset # type: unset # range: unset portcon tcp 50 system:system:system:s0:c0.c1 # test 51: # protocol: unset # ports: (50100, 50110) # user: unset # role: unset # type: unset # range: unset portcon tcp 50100-50110 system:system:system:s0:c0.c1 # test 52: # protocol: unset # ports: (50200, 50200), subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50200 system:system:system:s0:c0.c1 # test 53: # protocol: unset # ports: (50301, 50309), subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50300-50310 system:system:system:s0:c0.c1 # test 54: # protocol: unset # ports: (50400, 50400), proper subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50400 system:system:system:s0:c0.c1 # test 55: # protocol: unset # ports: (50501, 50509), proper subset # user: unset # role: unset # type: unset # range: unset portcon tcp 50500-50510 system:system:system:s0:c0.c1 # test 56: # protocol: unset # ports: (50600, 50602), superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50601 system:system:system:s0:c0.c1 # test 57: # protocol: unset # ports: (50700, 50711), superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50700-50710 system:system:system:s0:c0.c1 # test 58: # protocol: unset # ports: (50600, 50602), proper superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50801 system:system:system:s0:c0.c1 # test 59: # protocol: unset # ports: (50900, 50911), proper superset # user: unset # role: unset # type: unset # range: unset portcon tcp 50901-50910 system:system:system:s0:c0.c1 # test 60: # protocol: unset # ports: (60001, 60001), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60001 system:system:system:s0:c0.c1 # test 61: # protocol: unset # ports: (60100, 60105), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60101-60110 system:system:system:s0:c0.c1 # test 62: # protocol: unset # ports: (60205, 60211), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60200-60210 system:system:system:s0:c0.c1 # test 63: # protocol: unset # ports: (60305, 60308), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60300-60310 system:system:system:s0:c0.c1 # test 64: # protocol: unset # ports: (60400, 60410), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60400-60410 system:system:system:s0:c0.c1 # test 65: # protocol: unset # ports: (60500, 60510), overlap # user: unset # role: unset # type: unset # range: unset portcon tcp 60501-60509 system:system:system:s0:c0.c1 netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 setools-4.4.0/tests/portconquery.py000066400000000000000000000433151402045477700175150ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from socket import IPPROTO_UDP from setools import PortconQuery from .policyrep.util import compile_policy class PortconQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/portconquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Portcon query with no criteria""" # query with no parameters gets all ports. rules = sorted(self.p.portcons()) q = PortconQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_protocol(self): """Portcon query with protocol match""" q = PortconQuery(self.p, protocol=IPPROTO_UDP) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(1, 1)], ports) def test_010_user_exact(self): """Portcon query with context user exact match""" q = PortconQuery(self.p, user="user10", user_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(10, 10)], ports) def test_011_user_regex(self): """Portcon query with context user regex match""" q = PortconQuery(self.p, user="user11(a|b)", user_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(11, 11), (11000, 11000)], ports) def test_020_role_exact(self): """Portcon query with context role exact match""" q = PortconQuery(self.p, role="role20_r", role_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(20, 20)], ports) def test_021_role_regex(self): """Portcon query with context role regex match""" q = PortconQuery(self.p, role="role21(a|c)_r", role_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(21, 21), (21001, 21001)], ports) def test_030_type_exact(self): """Portcon query with context type exact match""" q = PortconQuery(self.p, type_="type30", type_regex=False) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(30, 30)], ports) def test_031_type_regex(self): """Portcon query with context type regex match""" q = PortconQuery(self.p, type_="type31(b|c)", type_regex=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(31000, 31000), (31001, 31001)], ports) def test_040_range_exact(self): """Portcon query with context range exact match""" q = PortconQuery(self.p, range_="s0:c1 - s0:c0.c4") ports = sorted(p.ports for p in q.results()) self.assertListEqual([(40, 40)], ports) def test_041_range_overlap1(self): """Portcon query with context range overlap match (equal)""" q = PortconQuery(self.p, range_="s1:c1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap2(self): """Portcon query with context range overlap match (subset)""" q = PortconQuery(self.p, range_="s1:c1,c2 - s1:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap3(self): """Portcon query with context range overlap match (superset)""" q = PortconQuery(self.p, range_="s1 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap4(self): """Portcon query with context range overlap match (overlap low level)""" q = PortconQuery(self.p, range_="s1 - s1:c1,c2", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_041_range_overlap5(self): """Portcon query with context range overlap match (overlap high level)""" q = PortconQuery(self.p, range_="s1:c1,c2 - s1:c0.c4", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(41, 41)], ports) def test_042_range_subset1(self): """Portcon query with context range subset match""" q = PortconQuery(self.p, range_="s2:c1,c2 - s2:c0.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_042_range_subset2(self): """Portcon query with context range subset match (equal)""" q = PortconQuery(self.p, range_="s2:c1 - s2:c1.c3", range_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(42, 42)], ports) def test_043_range_superset1(self): """Portcon query with context range superset match""" q = PortconQuery(self.p, range_="s3 - s3:c0.c4", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_043_range_superset2(self): """Portcon query with context range superset match (equal)""" q = PortconQuery(self.p, range_="s3:c1 - s3:c1.c3", range_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(43, 43)], ports) def test_044_range_proper_subset1(self): """Portcon query with context range proper subset match""" q = PortconQuery(self.p, range_="s4:c1,c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset2(self): """Portcon query with context range proper subset match (equal)""" q = PortconQuery(self.p, range_="s4:c1 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_044_range_proper_subset3(self): """Portcon query with context range proper subset match (equal low only)""" q = PortconQuery(self.p, range_="s4:c1 - s4:c1.c2", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_044_range_proper_subset4(self): """Portcon query with context range proper subset match (equal high only)""" q = PortconQuery(self.p, range_="s4:c1,c2 - s4:c1.c3", range_subset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(44, 44)], ports) def test_045_range_proper_superset1(self): """Portcon query with context range proper superset match""" q = PortconQuery(self.p, range_="s5 - s5:c0.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset2(self): """Portcon query with context range proper superset match (equal)""" q = PortconQuery(self.p, range_="s5:c1 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_045_range_proper_superset3(self): """Portcon query with context range proper superset match (equal low)""" q = PortconQuery(self.p, range_="s5:c1 - s5:c1.c4", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_045_range_proper_superset4(self): """Portcon query with context range proper superset match (equal high)""" q = PortconQuery(self.p, range_="s5 - s5:c1.c3", range_superset=True, range_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(45, 45)], ports) def test_050_single_equal(self): """Portcon query with single port exact match""" q = PortconQuery(self.p, ports=(50, 50)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50, 50)], ports) def test_051_range_equal(self): """Portcon query with port range exact match""" q = PortconQuery(self.p, ports=(50100, 50110)) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50100, 50110)], ports) def test_052_single_subset(self): """Portcon query with single port subset""" q = PortconQuery(self.p, ports=(50200, 50200), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50200, 50200)], ports) def test_053_range_subset(self): """Portcon query with range subset""" q = PortconQuery(self.p, ports=(50301, 50309), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_053_range_subset_edge1(self): """Portcon query with range subset, equal edge case""" q = PortconQuery(self.p, ports=(50300, 50310), ports_subset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50300, 50310)], ports) def test_054_single_proper_subset(self): """Portcon query with single port proper subset""" q = PortconQuery( self.p, ports=(50400, 50400), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset(self): """Portcon query with range proper subset""" q = PortconQuery( self.p, ports=(50501, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge1(self): """Portcon query with range proper subset, equal edge case""" q = PortconQuery( self.p, ports=(50500, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_055_range_proper_subset_edge2(self): """Portcon query with range proper subset, low equal edge case""" q = PortconQuery( self.p, ports=(50500, 50509), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_055_range_proper_subset_edge3(self): """Portcon query with range proper subset, high equal edge case""" q = PortconQuery( self.p, ports=(50501, 50510), ports_subset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50500, 50510)], ports) def test_056_single_superset(self): """Portcon query with single port superset""" q = PortconQuery(self.p, ports=(50600, 50602), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_056_single_superset_edge1(self): """Portcon query with single port superset, equal edge case""" q = PortconQuery(self.p, ports=(50601, 50601), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50601, 50601)], ports) def test_057_range_superset(self): """Portcon query with range superset""" q = PortconQuery(self.p, ports=(50700, 50711), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_057_range_superset_edge1(self): """Portcon query with range superset, equal edge case""" q = PortconQuery(self.p, ports=(50700, 50710), ports_superset=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50700, 50710)], ports) def test_058_single_proper_superset(self): """Portcon query with single port proper superset""" q = PortconQuery( self.p, ports=(50800, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge1(self): """Portcon query with single port proper superset, equal edge case""" q = PortconQuery( self.p, ports=(50801, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_058_single_proper_superset_edge2(self): """Portcon query with single port proper superset, low equal edge case""" q = PortconQuery( self.p, ports=(50801, 50802), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_058_single_proper_superset_edge3(self): """Portcon query with single port proper superset, high equal edge case""" q = PortconQuery( self.p, ports=(50800, 50801), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50801, 50801)], ports) def test_059_range_proper_superset(self): """Portcon query with range proper superset""" q = PortconQuery( self.p, ports=(50900, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge1(self): """Portcon query with range proper superset, equal edge case""" q = PortconQuery( self.p, ports=(50901, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([], ports) def test_059_range_proper_superset_edge2(self): """Portcon query with range proper superset, equal high port edge case""" q = PortconQuery( self.p, ports=(50900, 50910), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_059_range_proper_superset_edge3(self): """Portcon query with range proper superset, equal low port edge case""" q = PortconQuery( self.p, ports=(50901, 50911), ports_superset=True, ports_proper=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(50901, 50910)], ports) def test_060_single_overlap(self): """Portcon query with single overlap""" q = PortconQuery(self.p, ports=(60001, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge1(self): """Portcon query with single overlap, range match low""" q = PortconQuery(self.p, ports=(60001, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge2(self): """Portcon query with single overlap, range match high""" q = PortconQuery(self.p, ports=(60000, 60001), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_060_single_overlap_edge3(self): """Portcon query with single overlap, range match proper superset""" q = PortconQuery(self.p, ports=(60000, 60002), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60001, 60001)], ports) def test_061_range_overlap_low_half(self): """Portcon query with range overlap, low half match""" q = PortconQuery(self.p, ports=(60100, 60105), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60101, 60110)], ports) def test_062_range_overlap_high_half(self): """Portcon query with range overlap, high half match""" q = PortconQuery(self.p, ports=(60205, 60211), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60200, 60210)], ports) def test_063_range_overlap_middle(self): """Portcon query with range overlap, middle match""" q = PortconQuery(self.p, ports=(60305, 60308), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60300, 60310)], ports) def test_064_range_overlap_equal(self): """Portcon query with range overlap, equal match""" q = PortconQuery(self.p, ports=(60400, 60410), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60400, 60410)], ports) def test_065_range_overlap_superset(self): """Portcon query with range overlap, superset match""" q = PortconQuery(self.p, ports=(60500, 60510), ports_overlap=True) ports = sorted(p.ports for p in q.results()) self.assertListEqual([(60501, 60509)], ports) setools-4.4.0/tests/rbacrulequery.conf000066400000000000000000000110061402045477700201150ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 class process sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } class process inherits infoflow { transition } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; allow system system:infoflow3 null; ################################################################################ # RBAC # test 1 # ruletype: unset # source: test1s, direct, no regex # target: unset # class: unset # default: unset role test1s; role test1t; allow test1s test1t; role_transition test1s system:infoflow test1t; # test 2 # ruletype: unset # source: test2s, direct, regex # target: unset # class: unset # default: unset role test2s1; role test2s2; role test2s3; role test2t; allow test2s1 test2t; role_transition test2s3 system:infoflow test2t; # test 10 # ruletype: unset # source: unset # target: test10t, direct, no regex # class: unset # default: unset role test10s; role test10t; allow test10s test10t; role_transition test10s system:infoflow test10t; # test 11 # ruletype: unset # source: unset # target: test11t(1|3), direct, regex # class: unset # default: unset role test11s; role test11t1; role test11t2; role test11t3; allow test11s test11t1; role_transition test11s system:infoflow test11t3; # test 12 # ruletype: unset # source: unset # target: test12t # class: unset # default: unset role test12s; type test12t; role test12d; allow test12s test12d; role_transition test12s test12t:infoflow test12d; # test 20 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # default: unset role test20; role test20d1; role test20d2; role_transition test20 system:infoflow test20d1; role_transition test20 system:infoflow2 test20d2; # test 21 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # default: unset role test21; role test21d1; role test21d2; role test21d3; role_transition test21 system:infoflow test21d1; role_transition test21 system:infoflow4 test21d2; role_transition test21 system:infoflow3 test21d3; # test 22 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # default: unset role test22; role test22d1; role test22d2; role test22d3; role_transition test22 system:infoflow test22d1; role_transition test22 system:infoflow5 test22d2; role_transition test22 system:infoflow6 test22d3; # test 30 # ruletype: unset # source: unset # target: unset # class: unset # default: test30d, no regex role test30s; role test30d; allow test30s test30d; role_transition test30s system:infoflow test30d; # test 31 # ruletype: unset # source: unset # target: unset # class: unset # default: test31d(2|3), regex role test31s; role test31d1; role test31d2; role test31d3; allow test31s test31d1; allow test31s test31d2; allow test31s test31d3; role_transition test31s system:infoflow test31d1; role_transition test31s system test31d2; role_transition test31s system:infoflow7 test31d3; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/rbacrulequery.py000066400000000000000000000142611402045477700176260ustar00rootroot00000000000000"""RBAC rule query unit tests.""" # Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # pylint: disable=invalid-name,too-many-public-methods import os import unittest from setools import RBACRuleQuery from setools import RBACRuletype as RRT from setools.exception import RuleUseError, RuleNotConditional from . import mixins from .policyrep.util import compile_policy class RBACRuleQueryTest(mixins.ValidateRule, unittest.TestCase): """RBAC rule query unit tests.""" @classmethod def setUpClass(cls): cls.p = compile_policy("tests/rbacrulequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def validate_allow(self, rule, source, target): """Validate a role allow rule.""" self.assertEqual(RRT.allow, rule.ruletype) self.assertEqual(source, rule.source) self.assertEqual(target, rule.target) self.assertRaises(RuleUseError, getattr, rule, "tclass") self.assertRaises(RuleUseError, getattr, rule, "default") self.assertRaises(RuleNotConditional, getattr, rule, "conditional") def test_000_unset(self): """RBAC rule query with no criteria.""" # query with no parameters gets all RBAC rules. rules = sorted(self.p.rbacrules()) q = RBACRuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """RBAC rule query with exact, direct, source match.""" q = RBACRuleQuery( self.p, source="test1s", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_allow(r[0], "test1s", "test1t") self.validate_rule(r[1], RRT.role_transition, "test1s", "system", "infoflow", "test1t") def test_002_source_direct_regex(self): """RBAC rule query with regex, direct, source match.""" q = RBACRuleQuery( self.p, source="test2s(1|2)", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test2s1", "test2t") def test_010_target_direct(self): """RBAC rule query with exact, direct, target match.""" q = RBACRuleQuery( self.p, target="test10t", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test10s", "test10t") def test_011_target_direct_regex(self): """RBAC rule query with regex, direct, target match.""" q = RBACRuleQuery( self.p, target="test11t(1|3)", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_allow(r[0], "test11s", "test11t1") def test_012_target_type(self): """RBAC rule query with a type as target.""" q = RBACRuleQuery(self.p, target="test12t") r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test12s", "test12t", "infoflow", "test12d") @unittest.skip("Setting tclass to a string is no longer supported.") def test_020_class(self): """RBAC rule query with exact object class match.""" q = RBACRuleQuery(self.p, tclass="infoflow2", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test20", "system", "infoflow2", "test20d2") def test_021_class_list(self): """RBAC rule query with object class list match.""" q = RBACRuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test21", "system", "infoflow3", "test21d3") self.validate_rule(r[1], RRT.role_transition, "test21", "system", "infoflow4", "test21d2") def test_022_class_regex(self): """RBAC rule query with object class regex match.""" q = RBACRuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test22", "system", "infoflow5", "test22d2") self.validate_rule(r[1], RRT.role_transition, "test22", "system", "infoflow6", "test22d3") def test_030_default(self): """RBAC rule query with exact default match.""" q = RBACRuleQuery( self.p, default="test30d", default_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], RRT.role_transition, "test30s", "system", "infoflow", "test30d") def test_031_default_regex(self): """RBAC rule query with regex default match.""" q = RBACRuleQuery( self.p, default="test31d(2|3)", default_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], RRT.role_transition, "test31s", "system", "infoflow7", "test31d3") self.validate_rule(r[1], RRT.role_transition, "test31s", "system", "process", "test31d2") def test_040_ruletype(self): """RBAC rule query with rule type.""" q = RBACRuleQuery(self.p, ruletype=[RRT.allow]) num = 0 for num, r in enumerate(sorted(q.results()), start=1): self.assertEqual(r.ruletype, RRT.allow) # this will have to be updated as number of # role allows change in the test policy self.assertEqual(num, 9) setools-4.4.0/tests/rolequery.conf000066400000000000000000000067521402045477700172730ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # Role Query # # test 1 # name: test1 # types: unset role test1; # test 2 # name: test2(a|b) regex # types: unset role test2a; role test2b; # test 10 # name: unset # types: test10a,test10b type test10a; type test10b; type test10c; role test10r1; role test10r2; role test10r3; role test10r4; role test10r5; role test10r6; role test10r7; role test10r1 types test10a; role test10r2 types { test10a test10b }; role test10r3 types { test10a test10b test10c }; role test10r4 types { test10b test10c }; role test10r5 types { test10a test10c }; role test10r6 types test10b; role test10r7 types test10c; # test 11 # name: unset # types: test11a,test11b equal type test11a; type test11b; type test11c; role test11r1; role test11r2; role test11r3; role test11r4; role test11r5; role test11r6; role test11r7; role test11r1 types test11a; role test11r2 types { test11a test11b }; role test11r3 types { test11a test11b test11c }; role test11r4 types { test11b test11c }; role test11r5 types { test11a test11c }; role test11r6 types test11b; role test11r7 types test11c; # test 12 # name: unset # types: test12(a|b) regex type test12a; type test12b; type test12c; role test12r1; role test12r2; role test12r3; role test12r4; role test12r5; role test12r6; role test12r7; role test12r1 types test12a; role test12r2 types { test12a test12b }; role test12r3 types { test12a test12b test12c }; role test12r4 types { test12b test12c }; role test12r5 types { test12a test12c }; role test12r6 types test12b; role test12r7 types test12c; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/rolequery.py000066400000000000000000000052661402045477700167750ustar00rootroot00000000000000# Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import RoleQuery from .policyrep.util import compile_policy class RoleQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/rolequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Role query with no criteria.""" # query with no parameters gets all types. roles = sorted(self.p.roles()) q = RoleQuery(self.p) q_roles = sorted(q.results()) self.assertListEqual(roles, q_roles) def test_001_name_exact(self): """Role query with exact name match.""" q = RoleQuery(self.p, name="test1") roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test1"], roles) def test_002_name_regex(self): """Role query with regex name match.""" q = RoleQuery(self.p, name="test2(a|b)", name_regex=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test2a", "test2b"], roles) def test_010_type_intersect(self): """Role query with type set intersection.""" q = RoleQuery(self.p, types=["test10a", "test10b"]) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test10r1", "test10r2", "test10r3", "test10r4", "test10r5", "test10r6"], roles) def test_011_type_equality(self): """Role query with type set equality.""" q = RoleQuery(self.p, types=["test11a", "test11b"], types_equal=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test11r2"], roles) def test_012_type_regex(self): """Role query with type set match.""" q = RoleQuery(self.p, types="test12(a|b)", types_regex=True) roles = sorted(str(r) for r in q.results()) self.assertListEqual(["test12r1", "test12r2", "test12r3", "test12r4", "test12r5", "test12r6"], roles) setools-4.4.0/tests/sensitivityquery.conf000066400000000000000000000056201402045477700207150ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity sens; # test1 # name: test1 # alias: unset # sens: unset sensitivity test1; # test2 # name: test2(a|b) # alias: unset # sens: unset sensitivity test2a; sensitivity test2b; # test 10 # name: unset # alias: test10a # sens: unset sensitivity test10s1 alias { test10a test10c }; sensitivity test10s2 alias { test10b test10d }; # test 11 # name: unset # alias: test11(a|b) # sens: unset sensitivity test11s1 alias { test11a test11c }; sensitivity test11s2 alias { test11b test11d }; sensitivity test11s3 alias { test11e test11f }; # test 20 # name: unset # alias: unset # sens: test20 sensitivity test20; # test 21 # name: unset # alias: unset # sens: test21crit, dom sensitivity test21; sensitivity test21crit; # test 22 # name: unset # alias: unset # sens: test22crit, domby sensitivity test22; sensitivity test22crit; dominance { test21 test21crit test1 test2a test2b test10s1 sens test10s2 test11s1 test11s2 test11s3 test20 test22crit test22 } category begin; category end; #level decl level sens:begin.end; level test1; level test2a; level test2b; level test10s1; level test10s2; level test11s1; level test11s2; level test11s3; level test20; level test21; level test21crit; level test22; level test22crit; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ################################################################################ #users user system roles system level sens range sens - sens:begin.end; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:sens:begin sid security system:system:system:sens:begin #fs_use fs_use_trans devpts system:object_r:system:sens; fs_use_xattr ext3 system:object_r:system:sens; fs_use_task pipefs system:object_r:system:sens; #genfscon genfscon proc / system:object_r:system:sens genfscon proc /sys system:object_r:system:sens genfscon selinuxfs / system:object_r:system:sens:begin.end portcon tcp 80 system:object_r:system:sens netifcon eth0 system:object_r:system:sens system:object_r:system:sens nodecon 127.0.0.1 255.255.255.255 system:object_r:system:sens:begin nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:sens:begin setools-4.4.0/tests/sensitivityquery.py000066400000000000000000000072351402045477700204240ustar00rootroot00000000000000# Copyright 2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import SensitivityQuery from .policyrep.util import compile_policy class SensitivityQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/sensitivityquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Sensitivity query with no criteria.""" # query with no parameters gets all sensitivities. allsens = sorted(str(c) for c in self.p.sensitivities()) q = SensitivityQuery(self.p) qsens = sorted(str(c) for c in q.results()) self.assertListEqual(allsens, qsens) def test_001_name_exact(self): """Sensitivity query with exact name match.""" q = SensitivityQuery(self.p, name="test1") sens = sorted(str(c) for c in q.results()) self.assertListEqual(["test1"], sens) def test_002_name_regex(self): """Sensitivity query with regex name match.""" q = SensitivityQuery(self.p, name="test2(a|b)", name_regex=True) sens = sorted(str(c) for c in q.results()) self.assertListEqual(["test2a", "test2b"], sens) def test_010_alias_exact(self): """Sensitivity query with exact alias match.""" q = SensitivityQuery(self.p, alias="test10a") sens = sorted(str(t) for t in q.results()) self.assertListEqual(["test10s1"], sens) def test_011_alias_regex(self): """Sensitivity query with regex alias match.""" q = SensitivityQuery(self.p, alias="test11(a|b)", alias_regex=True) sens = sorted(str(t) for t in q.results()) self.assertListEqual(["test11s1", "test11s2"], sens) def test_020_sens_equal(self): """Sensitivity query with sens equality.""" q = SensitivityQuery(self.p, sens="test20") sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test20"], sens) def test_021_sens_dom1(self): """Sensitivity query with sens dominance.""" q = SensitivityQuery(self.p, sens="test21crit", sens_dom=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test21", "test21crit"], sens) def test_021_sens_dom2(self): """Sensitivity query with sens dominance (equal).""" q = SensitivityQuery(self.p, sens="test21", sens_dom=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], sens) def test_022_sens_domby1(self): """Sensitivity query with sens dominated-by.""" q = SensitivityQuery(self.p, sens="test22crit", sens_domby=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test22", "test22crit"], sens) def test_022_sens_domby2(self): """Sensitivity query with sens dominated-by (equal).""" q = SensitivityQuery(self.p, sens="test22", sens_domby=True) sens = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], sens) setools-4.4.0/tests/terulequery.conf000066400000000000000000000212421402045477700176210ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules ######################################## # # TE Rule Query # # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # perms: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; allow test1a test1t:infoflow hi_w; allow test1FAIL self:infoflow hi_w; # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # perms: unset attribute test2a; type test2s, test2a; type test2t; allow test2a test2t:infoflow hi_w; #allow test2s test2t:infoflow low_r; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # perms: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; allow test3s test3t:infoflow hi_w; allow test3aS test3t:infoflow low_r; allow test3b test3t:infoflow med_w; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # perms: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; allow test4a1 test4a1:infoflow hi_w; allow test4a2 test4a2:infoflow low_r; allow test4FAIL self:infoflow med_w; # test 5 # ruletype: unset # source: unset # target: test5a, direct, no regex # class: unset # perms: unset attribute test5a; type test5s; type test5t, test5a; allow test5s test5a:infoflow hi_w; allow test5s test5t:infoflow hi_w; # test 6 # ruletype: unset # source: unset # target: test6t, indirect, no regex # class: unset # perms: unset attribute test6a; type test6s; type test6t, test6a; allow test6s test6a:infoflow hi_w; allow test6s test6t:infoflow low_r; # test 7 # ruletype: unset # source: unset # target: test7a.*, direct, regex # class: unset # perms: unset attribute test7aPASS; attribute test7b; type test7s; type test7t, test7aPASS; type test7aFAIL, test7b; allow test7s test7t:infoflow hi_w; allow test7s test7aPASS:infoflow low_r; allow test7s test7b:infoflow med_w; # test 8 # ruletype: unset # source: unset # target: test8(s|t), indirect, regex # class: unset # perms: unset attribute test8a1; attribute test8a2; type test8s1, test8a1; type test8t1, test8a2; type test8FAIL; allow test8a1 test8a1:infoflow hi_w; allow test8a2 test8a2:infoflow low_r; allow test8FAIL self:infoflow med_w; # test 9 # ruletype: unset # source: unset # target: unset # class: infoflow2, no regex # perms: unset type test9; allow test9 self:infoflow hi_w; allow test9 self:infoflow2 super_w; # test 10 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # perms: unset type test10; allow test10 self:infoflow hi_w; allow test10 self:infoflow4 hi_w; allow test10 self:infoflow3 null; # test 11 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # perms: unset type test11; allow test11 self:infoflow hi_w; allow test11 self:infoflow5 low_w; allow test11 self:infoflow6 med_r; # test 12 # ruletype: unset # source: unset # target: unset # class: unset # perms: super_r, any type test12a; type test12b; allow test12a self:infoflow7 super_r; allow test12b self:infoflow7 { super_r super_none }; # test 13 # ruletype: unset # source: unset # target: unset # class: unset # perms: super_w,super_none,super_both equal type test13a; type test13b; type test13c; type test13d; allow test13a self:infoflow7 super_w; allow test13b self:infoflow7 { super_w super_none }; allow test13c self:infoflow7 { super_w super_none super_both }; allow test13d self:infoflow7 { super_w super_none super_both super_unmapped }; # test 14 # ruletype: dontaudit,auditallow # source: unset # target: unset # class: unset # perms: unset type test14; auditallow test14 self:infoflow7 super_both; dontaudit test14 self:infoflow7 super_unmapped; # test 100 # ruletype: unset # source: unset # target: unset # class: unset # default: test100d type test100; type test100d; type_transition test100 test100:infoflow7 test100d; # test 101 # ruletype: unset # source: unset # target: unset # class: unset # default: test101. type test101; type test101d; type test101e; type_transition test101 test101d:infoflow7 test101e; type_transition test101 test101e:infoflow7 test101d; # test 200 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test200 type test200t1; type test200t2; bool test200 false; bool test200a true; if (test200) { allow test200t1 self:infoflow7 super_w; } if (test200 && test200a) { allow test200t2 self:infoflow7 super_w; } # test 201 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test201a test201b type test201t1; type test201t2; bool test201a false; bool test201b true; if (test201a) { allow test201t1 self:infoflow7 super_w; } if (test201b) { allow test201t2 self:infoflow7 super_w; } if (test201a && test201b) { allow test201t1 self:infoflow7 super_unmapped; } # test 202 # ruletype: unset # source: unset # target: unset # class: unset # default: unset # boolean: test202(a|b) type test202t1; type test202t2; bool test202a false; bool test202b true; bool test202c true; if (test202a) { allow test202t1 self:infoflow7 super_none; } if (test202c) { allow test202t2 self:infoflow7 super_both; } if (test202c || test202b) { allow test202t2 self:infoflow7 super_unmapped; } # test 300 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with source criteria that is an attribute, indirect match # # ruletype: unset # source: test300b, indirect # target: unset # class: unset # default: unset # boolean: unset attribute test300a; attribute test300b; type test300t1, test300a, test300b; type test300t2, test300b; type test300t3, test300a; type test300target; allow test300a test300target:infoflow7 hi_w; allow test300t1 self:infoflow7 hi_r; allow test300t2 self:infoflow7 med_w; allow test300b test300target:infoflow7 super_w; # test 301 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with target criteria that is an attribute, indirect match # # ruletype: unset # source: unset # target: test301b, indirect # class: unset # default: unset # boolean: unset attribute test301a; attribute test301b; type test301t1, test301a, test301b; type test301t2, test301b; type test301t3, test301a; type test301source; allow test301source test301a:infoflow7 hi_w; allow test301t1 self:infoflow7 hi_r; allow test301t2 self:infoflow7 med_w; allow test301source test301b:infoflow7 super_w; # test 302 # https://github.com/TresysTechnology/setools/issues/111 # Fix search with default type criteria that is an attribute # # ruletype: unset # source: unset # target: unset # class: unset # default: test302b # boolean: unset attribute test302; type test302t1, test302; type test302t2, test302; type test302source; type_transition test302source test302t1:infoflow7 test302t1; type_transition test302source test302t2:infoflow7 test302t2; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/terulequery.py000066400000000000000000000511631402045477700173310ustar00rootroot00000000000000"""Type enforcement rule query unit tests.""" # Copyright 2014, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # # pylint: disable=invalid-name,too-many-public-methods import os import unittest from setools import TERuleQuery from setools import TERuletype as TRT from . import mixins from .policyrep.util import compile_policy class TERuleQueryTest(mixins.ValidateRule, unittest.TestCase): """Type enforcement rule query unit tests.""" @classmethod def setUpClass(cls): cls.p = compile_policy("tests/terulequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """TE rule query with no criteria.""" # query with no parameters gets all TE rules. rules = sorted(self.p.terules()) q = TERuleQuery(self.p) q_rules = sorted(q.results()) self.assertListEqual(rules, q_rules) def test_001_source_direct(self): """TE rule query with exact, direct, source match.""" q = TERuleQuery( self.p, source="test1a", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test1a", "test1t", "infoflow", set(["hi_w"])) def test_002_source_indirect(self): """TE rule query with exact, indirect, source match.""" q = TERuleQuery( self.p, source="test2s", source_indirect=True, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test2a", "test2t", "infoflow", set(["hi_w"])) def test_003_source_direct_regex(self): """TE rule query with regex, direct, source match.""" q = TERuleQuery( self.p, source="test3a.*", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test3aS", "test3t", "infoflow", set(["low_r"])) def test_004_source_indirect_regex(self): """TE rule query with regex, indirect, source match.""" q = TERuleQuery( self.p, source="test4(s|t)", source_indirect=True, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test4a1", "test4a1", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test4a2", "test4a2", "infoflow", set(["low_r"])) def test_005_target_direct(self): """TE rule query with exact, direct, target match.""" q = TERuleQuery( self.p, target="test5a", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test5s", "test5a", "infoflow", set(["hi_w"])) def test_006_target_indirect(self): """TE rule query with exact, indirect, target match.""" q = TERuleQuery( self.p, target="test6t", target_indirect=True, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test6s", "test6a", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test6s", "test6t", "infoflow", set(["low_r"])) def test_007_target_direct_regex(self): """TE rule query with regex, direct, target match.""" q = TERuleQuery( self.p, target="test7a.*", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test7s", "test7aPASS", "infoflow", set(["low_r"])) def test_008_target_indirect_regex(self): """TE rule query with regex, indirect, target match.""" q = TERuleQuery( self.p, target="test8(s|t)", target_indirect=True, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test8a1", "test8a1", "infoflow", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test8a2", "test8a2", "infoflow", set(["low_r"])) @unittest.skip("Setting tclass to a string is no longer supported.") def test_009_class(self): """TE rule query with exact object class match.""" q = TERuleQuery(self.p, tclass="infoflow2", tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test9", "test9", "infoflow2", set(["super_w"])) def test_010_class_list(self): """TE rule query with object class list match.""" q = TERuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test10", "test10", "infoflow3", set(["null"])) self.validate_rule(r[1], TRT.allow, "test10", "test10", "infoflow4", set(["hi_w"])) def test_011_class_regex(self): """TE rule query with object class regex match.""" q = TERuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test11", "test11", "infoflow5", set(["low_w"])) self.validate_rule(r[1], TRT.allow, "test11", "test11", "infoflow6", set(["med_r"])) def test_012_perms_any(self): """TE rule query with permission set intersection.""" q = TERuleQuery(self.p, perms=["super_r"], perms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test12a", "test12a", "infoflow7", set(["super_r"])) self.validate_rule(r[1], TRT.allow, "test12b", "test12b", "infoflow7", set(["super_r", "super_none"])) def test_013_perms_equal(self): """TE rule query with permission set equality.""" q = TERuleQuery( self.p, perms=["super_w", "super_none", "super_both"], perms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test13c", "test13c", "infoflow7", set(["super_w", "super_none", "super_both"])) def test_014_ruletype(self): """TE rule query with rule type match.""" q = TERuleQuery(self.p, ruletype=["auditallow", "dontaudit"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.auditallow, "test14", "test14", "infoflow7", set(["super_both"])) self.validate_rule(r[1], TRT.dontaudit, "test14", "test14", "infoflow7", set(["super_unmapped"])) def test_052_perms_subset1(self): """TE rule query with permission subset.""" q = TERuleQuery(self.p, perms=["super_none", "super_both"], perms_subset=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test13c", "test13c", "infoflow7", set(["super_w", "super_none", "super_both"])) self.validate_rule(r[1], TRT.allow, "test13d", "test13d", "infoflow7", set(["super_w", "super_none", "super_both", "super_unmapped"])) def test_052_perms_subset2(self): """TE rule query with permission subset (equality).""" q = TERuleQuery(self.p, perms=["super_w", "super_none", "super_both", "super_unmapped"], perms_subset=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test13d", "test13d", "infoflow7", set(["super_w", "super_none", "super_both", "super_unmapped"])) def test_100_default(self): """TE rule query with default type exact match.""" q = TERuleQuery(self.p, default="test100d", default_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.type_transition, "test100", "test100", "infoflow7", "test100d") def test_101_default_regex(self): """TE rule query with default type regex match.""" q = TERuleQuery(self.p, default="test101.", default_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.type_transition, "test101", "test101d", "infoflow7", "test101e") self.validate_rule(r[1], TRT.type_transition, "test101", "test101e", "infoflow7", "test101d") def test_200_boolean_intersection(self): """TE rule query with intersection Boolean set match.""" q = TERuleQuery(self.p, boolean=["test200"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test200t1", "test200t1", "infoflow7", set(["super_w"]), cond="test200") self.validate_rule(r[1], TRT.allow, "test200t2", "test200t2", "infoflow7", set(["super_w"]), cond="test200a && test200") def test_201_boolean_equal(self): """TE rule query with equal Boolean set match.""" q = TERuleQuery(self.p, boolean=["test201a", "test201b"], boolean_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allow, "test201t1", "test201t1", "infoflow7", set(["super_unmapped"]), cond="test201b && test201a") def test_202_boolean_regex(self): """TE rule query with regex Boolean match.""" q = TERuleQuery(self.p, boolean="test202(a|b)", boolean_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allow, "test202t1", "test202t1", "infoflow7", set(["super_none"]), cond="test202a") self.validate_rule(r[1], TRT.allow, "test202t2", "test202t2", "infoflow7", set(["super_unmapped"]), cond="test202b || test202c") def test_300_issue111(self): """TE rule query with attribute source criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, source="test300b", source_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allow, "test300a", "test300target", "infoflow7", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test300b", "test300target", "infoflow7", set(["super_w"])) self.validate_rule(r[2], TRT.allow, "test300t1", "test300t1", "infoflow7", set(["hi_r"])) self.validate_rule(r[3], TRT.allow, "test300t2", "test300t2", "infoflow7", set(["med_w"])) def test_301_issue111(self): """TE rule query with attribute target criteria, indirect match.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, target="test301b", target_indirect=True) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allow, "test301source", "test301a", "infoflow7", set(["hi_w"])) self.validate_rule(r[1], TRT.allow, "test301source", "test301b", "infoflow7", set(["super_w"])) self.validate_rule(r[2], TRT.allow, "test301t1", "test301t1", "infoflow7", set(["hi_r"])) self.validate_rule(r[3], TRT.allow, "test301t2", "test301t2", "infoflow7", set(["med_w"])) def test_302_issue111(self): """TE rule query with attribute default type criteria.""" # https://github.com/TresysTechnology/setools/issues/111 q = TERuleQuery(self.p, default="test302") r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.type_transition, "test302source", "test302t1", "infoflow7", "test302t1") self.validate_rule(r[1], TRT.type_transition, "test302source", "test302t2", "infoflow7", "test302t2") class TERuleQueryXperm(mixins.ValidateRule, unittest.TestCase): """TE Rule Query with extended permission rules.""" @classmethod def setUpClass(cls): cls.p = compile_policy("tests/terulequery2.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_001_source_direct(self): """Xperm rule query with exact, direct, source match.""" q = TERuleQuery( self.p, source="test1a", source_indirect=False, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test1a", "test1t", "infoflow", set(range(0xebe0, 0xebff + 1)), xperm="ioctl") def test_002_source_indirect(self): """Xperm rule query with exact, indirect, source match.""" q = TERuleQuery( self.p, source="test2s", source_indirect=True, source_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test2a", "test2t", "infoflow", set([0x5411, 0x5451]), xperm="ioctl") def test_003_source_direct_regex(self): """Xperm rule query with regex, direct, source match.""" q = TERuleQuery( self.p, source="test3a.*", source_indirect=False, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test3aS", "test3t", "infoflow", set([0x1111]), xperm="ioctl") def test_004_source_indirect_regex(self): """Xperm rule query with regex, indirect, source match.""" q = TERuleQuery( self.p, source="test4(s|t)", source_indirect=True, source_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test4a1", "test4a1", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test4a2", "test4a2", "infoflow", set([0x1111]), xperm="ioctl") def test_005_target_direct(self): """Xperm rule query with exact, direct, target match.""" q = TERuleQuery( self.p, target="test5a", target_indirect=False, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test5s", "test5a", "infoflow", set([0x9999]), xperm="ioctl") def test_006_target_indirect(self): """Xperm rule query with exact, indirect, target match.""" q = TERuleQuery( self.p, target="test6t", target_indirect=True, target_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test6s", "test6a", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test6s", "test6t", "infoflow", set([0x1111]), xperm="ioctl") def test_007_target_direct_regex(self): """Xperm rule query with regex, direct, target match.""" q = TERuleQuery( self.p, target="test7a.*", target_indirect=False, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test7s", "test7aPASS", "infoflow", set([0x1111]), xperm="ioctl") def test_008_target_indirect_regex(self): """Xperm rule query with regex, indirect, target match.""" q = TERuleQuery( self.p, target="test8(s|t)", target_indirect=True, target_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test8a1", "test8a1", "infoflow", set([0x9999]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test8a2", "test8a2", "infoflow", set([0x1111]), xperm="ioctl") def test_010_class_list(self): """Xperm rule query with object class list match.""" q = TERuleQuery( self.p, tclass=["infoflow3", "infoflow4"], tclass_regex=False) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test10", "test10", "infoflow3", set([0]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test10", "test10", "infoflow4", set([0x9999]), xperm="ioctl") def test_011_class_regex(self): """Xperm rule query with object class regex match.""" q = TERuleQuery(self.p, tclass="infoflow(5|6)", tclass_regex=True) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.allowxperm, "test11", "test11", "infoflow5", set([0x1111]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test11", "test11", "infoflow6", set([0x5555]), xperm="ioctl") def test_014_ruletype(self): """Xperm rule query with rule type match.""" q = TERuleQuery(self.p, ruletype=["auditallowxperm", "dontauditxperm"]) r = sorted(q.results()) self.assertEqual(len(r), 2) self.validate_rule(r[0], TRT.auditallowxperm, "test14", "test14", "infoflow7", set([0x1234]), xperm="ioctl") self.validate_rule(r[1], TRT.dontauditxperm, "test14", "test14", "infoflow7", set([0x4321]), xperm="ioctl") def test_100_std_perm_any(self): """Xperm rule query match by standard permission.""" q = TERuleQuery(self.p, ruletype=["neverallow", "neverallowxperm"], perms=set(["ioctl", "hi_w"]), perms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 0) # changed after dropping source policy support # self.assertEqual(len(r), 2) # self.validate_rule(r[0], TRT.neverallow, "test100", "system", "infoflow2", # set(["ioctl", "hi_w"])) # self.validate_rule(r[1], TRT.neverallowxperm, "test100", "test100", "infoflow2", # set([0x1234]), xperm="ioctl") def test_100_std_perm_equal(self): """Xperm rule query match by standard permission, equal perm set.""" q = TERuleQuery(self.p, ruletype=["neverallow", "neverallowxperm"], perms=set(["ioctl", "hi_w"]), perms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 0) # changed after dropping source policy support # self.assertEqual(len(r), 1) # self.validate_rule(r[0], TRT.neverallow, "test100", "system", "infoflow2", # set(["ioctl", "hi_w"])) def test_101_xperm_any(self): """Xperm rule query match any perm set.""" q = TERuleQuery(self.p, xperms=[(0x9011, 0x9013)], xperms_equal=False) r = sorted(q.results()) self.assertEqual(len(r), 4) self.validate_rule(r[0], TRT.allowxperm, "test101a", "test101a", "infoflow7", set([0x9011]), xperm="ioctl") self.validate_rule(r[1], TRT.allowxperm, "test101b", "test101b", "infoflow7", set([0x9011, 0x9012]), xperm="ioctl") self.validate_rule(r[2], TRT.allowxperm, "test101c", "test101c", "infoflow7", set([0x9011, 0x9012, 0x9013]), xperm="ioctl") self.validate_rule(r[3], TRT.allowxperm, "test101d", "test101d", "infoflow7", set([0x9011, 0x9012, 0x9013, 0x9014]), xperm="ioctl") def test_101_xperm_equal(self): """Xperm rule query match equal perm set.""" q = TERuleQuery(self.p, xperms=[(0x9011, 0x9013)], xperms_equal=True) r = sorted(q.results()) self.assertEqual(len(r), 1) self.validate_rule(r[0], TRT.allowxperm, "test101c", "test101c", "infoflow7", set([0x9011, 0x9012, 0x9013]), xperm="ioctl") setools-4.4.0/tests/terulequery2.conf000066400000000000000000000133151402045477700177050ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r ioctl } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { ioctl } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; ######################################### # XPERM ioctl declarations and rules # test 1 # ruletype: unset # source: test1a, direct, no regex # target: unset # class: unset # perms: unset attribute test1a; type test1s, test1a; type test1t; type test1FAIL, test1a; allowxperm test1a test1t:infoflow ioctl { 0xebe0-0xebff }; # sets AVRULE_XPERMS_IOCTLFUNCTION allowxperm test1FAIL self:infoflow ioctl { 0x8800-0x88ff }; # sets AVRULE_XPERMS_IOCTLDRIVER # test 2 # ruletype: unset # source: test2s, indirect, no regex # target: unset # class: unset # perms: unset attribute test2a; type test2s, test2a; type test2t; allowxperm test2a test2t:infoflow ioctl { 0x5411 0x5451 }; # test 3 # ruletype: unset # source: test3a.*, direct, regex # target: unset # class: unset # perms: unset attribute test3aS; attribute test3b; type test3s, test3aS; type test3t; type test3aFAIL, test3b; allowxperm test3s test3t:infoflow ioctl 0x9999; allowxperm test3aS test3t:infoflow ioctl 0x1111; allowxperm test3b test3t:infoflow ioctl 0x5555; # test 4 # ruletype: unset # source: test4(s|t), indirect, regex # target: unset # class: unset # perms: unset attribute test4a1; attribute test4a2; type test4s1, test4a1; type test4t1, test4a2; type test4FAIL; allowxperm test4a1 test4a1:infoflow ioctl 0x9999; allowxperm test4a2 test4a2:infoflow ioctl 0x1111; allowxperm test4FAIL self:infoflow ioctl 0x5555; # test 5 # ruletype: unset # source: unset # target: test5a, direct, no regex # class: unset # perms: unset attribute test5a; type test5s; type test5t, test5a; allowxperm test5s test5a:infoflow ioctl 0x9999; allowxperm test5s test5t:infoflow ioctl 0x9999; # test 6 # ruletype: unset # source: unset # target: test6t, indirect, no regex # class: unset # perms: unset attribute test6a; type test6s; type test6t, test6a; allowxperm test6s test6a:infoflow ioctl 0x9999; allowxperm test6s test6t:infoflow ioctl 0x1111; # test 7 # ruletype: unset # source: unset # target: test7a.*, direct, regex # class: unset # perms: unset attribute test7aPASS; attribute test7b; type test7s; type test7t, test7aPASS; type test7aFAIL, test7b; allowxperm test7s test7t:infoflow ioctl 0x9999; allowxperm test7s test7aPASS:infoflow ioctl 0x1111; allowxperm test7s test7b:infoflow ioctl 0x5555; # test 8 # ruletype: unset # source: unset # target: test8(s|t), indirect, regex # class: unset # perms: unset attribute test8a1; attribute test8a2; type test8s1, test8a1; type test8t1, test8a2; type test8FAIL; allowxperm test8a1 test8a1:infoflow ioctl 0x9999; allowxperm test8a2 test8a2:infoflow ioctl 0x1111; allowxperm test8FAIL self:infoflow ioctl 0x5555; # test 10 # ruletype: unset # source: unset # target: unset # class: infoflow3,infoflow4 , no regex # perms: unset type test10; allowxperm test10 self:infoflow ioctl 0x9999; allowxperm test10 self:infoflow4 ioctl 0x9999; allowxperm test10 self:infoflow3 ioctl 0x0; # test 11 # ruletype: unset # source: unset # target: unset # class: infoflow(5|6), regex # perms: unset type test11; allowxperm test11 self:infoflow ioctl 0x9999; allowxperm test11 self:infoflow5 ioctl 0x1111; allowxperm test11 self:infoflow6 ioctl 0x5555; # test 14 # ruletype: dontauditxperm,auditallowxperm # source: unset # target: unset # class: unset # perms: unset type test14; auditallowxperm test14 self:infoflow7 ioctl 0x1234; dontauditxperm test14 self:infoflow7 ioctl 0x4321; # test 100 # ruletype: neverallow, neverallowxperm # source: unset # target: unset # class: unset # perms: ioctl (standard) type test100; neverallow test100 system:infoflow2 { ioctl hi_w }; neverallowxperm test100 self:infoflow2 ioctl 0x1234; # test 101 # ruletype: unset # source: unset # target: unset # class: unset # perms: 0x9011-0x9013 type test101a; type test101b; type test101c; type test101d; allowxperm test101a self:infoflow7 ioctl 0x9011; allowxperm test101b self:infoflow7 ioctl { 0x9011-0x9012 }; allowxperm test101c self:infoflow7 ioctl { 0x9011-0x9013 }; allowxperm test101d self:infoflow7 ioctl { 0x9011-0x9014 }; ############# END XPERM ############################ role system; role system types system; #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/typeattrquery.conf000066400000000000000000000060511402045477700201760ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # Type Query # # test 1 # name: test1 # types: unset attribute test1; # test 2 # name: test2(a|b) regex # types: unset attribute test2a; attribute test2b; # test 10 # name: unset # types: attribute test10a; attribute test10b; attribute test10c; type test10t1, test10a; type test10t2, test10a, test10b; type test10t3, test10a, test10b, test10c; type test10t4, test10b, test10c; type test10t5, test10a, test10c; type test10t6, test10b; type test10t7, test10c; # test 11 # name: unset # types: attribute test11a; attribute test11b; attribute test11c; type test11t1, test11a; type test11t2, test11a, test11b; type test11t3, test11a, test11b, test11c; type test11t4, test11b, test11c; type test11t5, test11a, test11c; type test11t6, test11b; type test11t7, test11c; # test 12 # name: unset # types: attribute test12a; attribute test12b; attribute test12c; type test12t1, test12a; type test12t2, test12a, test12b; type test12t3, test12a, test12b, test12c; type test12t4, test12b, test12c; type test12t5, test12a, test12c; type test12t6, test12b; type test12t7, test12c; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/typeattrquery.py000066400000000000000000000054141402045477700177030ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import TypeAttributeQuery from .policyrep.util import compile_policy class TypeAttributeQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/typeattrquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Type attribute query with no criteria.""" # query with no parameters gets all attrs. allattrs = sorted(self.p.typeattributes()) q = TypeAttributeQuery(self.p) qattrs = sorted(q.results()) self.assertListEqual(allattrs, qattrs) def test_001_name_exact(self): """Type attribute query with exact name match.""" q = TypeAttributeQuery(self.p, name="test1") attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test1"], attrs) def test_002_name_regex(self): """Type attribute query with regex name match.""" q = TypeAttributeQuery(self.p, name="test2(a|b)", name_regex=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test2a", "test2b"], attrs) def test_010_type_set_intersect(self): """Type attribute query with type set intersection.""" q = TypeAttributeQuery(self.p, types=["test10t1", "test10t7"]) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test10a", "test10c"], attrs) def test_011_type_set_equality(self): """Type attribute query with type set equality.""" q = TypeAttributeQuery(self.p, types=["test11t1", "test11t2", "test11t3", "test11t5"], types_equal=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test11a"], attrs) def test_012_type_set_regex(self): """Type attribute query with type set regex match.""" q = TypeAttributeQuery(self.p, types="test12t(1|2)", types_regex=True) attrs = sorted(str(t) for t in q.results()) self.assertListEqual(["test12a", "test12b"], attrs) setools-4.4.0/tests/typequery.conf000066400000000000000000000072741402045477700173130ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity low_s; sensitivity medium_s alias med; sensitivity high_s; dominance { low_s med high_s } category here; category there; category elsewhere alias lost; #level decl level low_s:here.there; level med:here, elsewhere; level high_s:here.lost; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # Type Query # # test 1 # name: test1 # attrs: unset # alias: unset type test1; # test 2 # name: test2(a|b) regex # attrs: unset # alias: unset type test2a; type test2b; # test 10 # name: unset # attrs: test10a,test10b # alias: unset attribute test10a; attribute test10b; attribute test10c; type test10t1, test10a; type test10t2, test10a, test10b; type test10t3, test10a, test10b, test10c; type test10t4, test10b, test10c; type test10t5, test10a, test10c; type test10t6, test10b; type test10t7, test10c; # test 11 # name: unset # attrs: test11a,test11b equal # alias: unset attribute test11a; attribute test11b; attribute test11c; type test11t1, test11a; type test11t2, test11a, test11b; type test11t3, test11a, test11b, test11c; type test11t4, test11b, test11c; type test11t5, test11a, test11c; type test11t6, test11b; type test11t7, test11c; # test 12 # name: unset # attrs: test12(a|b) regex # alias: unset attribute test12a; attribute test12b; attribute test12c; type test12t1, test12a; type test12t2, test12a, test12b; type test12t3, test12a, test12b, test12c; type test12t4, test12b, test12c; type test12t5, test12a, test12c; type test12t6, test12b; type test12t7, test12c; # test 20 # name: unset # attrs: unset # alias: test20a type test20t1 alias { test20a test20c }; type test20t2 alias { test20b test20d }; # test 21 # name: unset # attrs: unset # alias: test21(a|b) type test21t1 alias { test21a test21c }; type test21t2 alias { test21b test21d }; type test21t3 alias { test21e test21f }; # test 22 # name: test22alias # deref: True # attrs: unset # alias: unset type test22 alias { test22alias test22a }; # test 30 # name: test30 # attrs: unset # alias: unset type test30; type test30a; permissive test30; ################################################################################ #users user system roles system level med range low_s - high_s:here.lost; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:medium_s:here sid security system:system:system:high_s:lost #fs_use fs_use_trans devpts system:object_r:system:low_s; fs_use_xattr ext3 system:object_r:system:low_s; fs_use_task pipefs system:object_r:system:low_s; #genfscon genfscon proc / system:object_r:system:med genfscon proc /sys system:object_r:system:low_s genfscon selinuxfs / system:object_r:system:high_s:here.there portcon tcp 80 system:object_r:system:low_s netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here setools-4.4.0/tests/typequery.py000066400000000000000000000073531402045477700170140ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # Copyright 2019, Chris PeBenito # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import TypeQuery from .policyrep.util import compile_policy class TypeQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/typequery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """Type query with no criteria.""" # query with no parameters gets all types. alltypes = sorted(self.p.types()) q = TypeQuery(self.p) qtypes = sorted(q.results()) self.assertListEqual(alltypes, qtypes) def test_001_name_exact(self): """Type query with exact name match.""" q = TypeQuery(self.p, name="test1") types = sorted(str(t) for t in q.results()) self.assertListEqual(["test1"], types) def test_002_name_regex(self): """Type query with regex name match.""" q = TypeQuery(self.p, name="test2(a|b)", name_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test2a", "test2b"], types) def test_010_attr_intersect(self): """Type query with attribute set intersection.""" q = TypeQuery(self.p, attrs=["test10a", "test10b"]) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test10t1", "test10t2", "test10t3", "test10t4", "test10t5", "test10t6"], types) def test_011_attr_equality(self): """Type query with attribute set equality.""" q = TypeQuery(self.p, attrs=["test11a", "test11b"], attrs_equal=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test11t2"], types) def test_012_attr_regex(self): """Type query with attribute regex match.""" q = TypeQuery(self.p, attrs="test12(a|b)", attrs_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test12t1", "test12t2", "test12t3", "test12t4", "test12t5", "test12t6"], types) def test_020_alias_exact(self): """Type query with exact alias match.""" q = TypeQuery(self.p, alias="test20a") types = sorted(str(t) for t in q.results()) self.assertListEqual(["test20t1"], types) def test_021_alias_regex(self): """Type query with regex alias match.""" q = TypeQuery(self.p, alias="test21(a|b)", alias_regex=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test21t1", "test21t2"], types) def test_022_alias_dereference(self): """Type query with alias dereference.""" q = TypeQuery(self.p, name="test22alias", alias_deref=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test22"], types) def test_030_permissive(self): """Type query with permissive match""" q = TypeQuery(self.p, permissive=True) types = sorted(str(t) for t in q.results()) self.assertListEqual(["test30"], types) setools-4.4.0/tests/userquery.conf000066400000000000000000000130151402045477700172760ustar00rootroot00000000000000class infoflow class infoflow2 class infoflow3 class infoflow4 class infoflow5 class infoflow6 class infoflow7 sid kernel sid security common infoflow { low_w med_w hi_w low_r med_r hi_r } class infoflow inherits infoflow class infoflow2 inherits infoflow { super_w super_r } class infoflow3 { null } class infoflow4 inherits infoflow class infoflow5 inherits infoflow class infoflow6 inherits infoflow class infoflow7 inherits infoflow { super_w super_r super_none super_both super_unmapped } sensitivity s0; sensitivity s1; sensitivity s2; sensitivity s3; sensitivity s4; sensitivity s5; sensitivity s6; dominance { s0 s1 s2 s3 s4 s5 s6 } category c0; category c1; category c2; category c3; category c4; category c5; category c6; category c7; #level decl level s0:c0.c7; level s1:c0.c7; level s2:c0.c7; level s3:c0.c7; level s4:c0.c7; level s5:c0.c7; level s6:c0.c7; #some constraints mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); attribute mls_exempt; type system; role system; role system types system; ################################################################################ # Type enforcement declarations and rules allow system system:infoflow3 null; ######################################## # # User Query # role test1_r; role test2a_r; role test2b_r; role test10a_r; role test10b_r; role test10c_r; role test11a_r; role test11b_r; role test11c_r; role test12a_r; role test12b_r; role test12c_r; # test 1 # name: test1_u # roles: unset user test1_u roles test1_r level s3:c5,c7 range s3:c5,c7; # test 2 # name: test2_u(1|2) regex # roles: unset user test2_u1 roles test2a_r level s3:c5,c7 range s3:c5,c7; user test2_u2 roles test2b_r level s3:c5,c7 range s3:c5,c7; # test 10 # name: unset # roles: test10a_r,test10b_r user test10_u1 roles test10a_r level s3:c5,c7 range s3:c5,c7; user test10_u2 roles { test10a_r test10b_r } level s3:c5,c7 range s3:c5,c7; user test10_u3 roles { test10a_r test10b_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u4 roles { test10b_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u5 roles { test10a_r test10c_r } level s3:c5,c7 range s3:c5,c7; user test10_u6 roles test10b_r level s3:c5,c7 range s3:c5,c7; user test10_u7 roles test10c_r level s3:c5,c7 range s3:c5,c7; # test 11 # name: unset # roles: test11a_r,test11b_r equal user test11_u1 roles test11a_r level s3:c5,c7 range s3:c5,c7; user test11_u2 roles { test11a_r test11b_r } level s3:c5,c7 range s3:c5,c7; user test11_u3 roles { test11a_r test11b_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u4 roles { test11b_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u5 roles { test11a_r test11c_r } level s3:c5,c7 range s3:c5,c7; user test11_u6 roles test11b_r level s3:c5,c7 range s3:c5,c7; user test11_u7 roles test11c_r level s3:c5,c7 range s3:c5,c7; # test 12 # name: unset # roles: test12(a|b)_r regex user test12_u1 roles test12a_r level s3:c5,c7 range s3:c5,c7; user test12_u2 roles { test12a_r test12b_r } level s3:c5,c7 range s3:c5,c7; user test12_u3 roles { test12a_r test12b_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u4 roles { test12b_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u5 roles { test12a_r test12c_r } level s3:c5,c7 range s3:c5,c7; user test12_u6 roles test12b_r level s3:c5,c7 range s3:c5,c7; user test12_u7 roles test12c_r level s3:c5,c7 range s3:c5,c7; # test 20 # name: unset # roles: unset # level: equal # range: unset user test20 roles system level s3:c0,c4 range s3 - s3:c0.c4,c7; # test 21 # name: unset # roles: unset # level: high, dom # range: unset user test21 roles system level s2:c1,c4 range s2 - s2:c0.c4,c7; # test 22 # name: unset # roles: unset # level: high, domby # range: unset user test22 roles system level s4:c2,c4 range s4 - s4:c0.c4,c7; # test 23 # name: unset # roles: unset # level: high, incomp # range: unset user test23 roles system level s3:c6 range s3 - s3:c0.c7; # test 40: # name: unset # roles: unset # level: unset # range: equal user test40 roles system level s0:c5 range s0:c5 - s0:c0.c5; # test 41: # name: unset # roles: unset # level: unset # range: overlap user test41 roles system level s1:c5 range s1:c5 - s1:c1.c3,c5; # test 42: # name: unset # roles: unset # level: unset # range: subset user test42 roles system level s2:c5 range s2:c5 - s2:c1.c3,c5; # test 43: # name: unset # roles: unset # level: unset # range: superset user test43 roles system level s3:c5 range s3:c5 - s3:c1.c3,c5,c6; # test 44: # name: unset # roles: unset # level: unset # range: proper subset user test44 roles system level s4:c5 range s4:c5 - s4:c1.c3,c5; # test 45: # name: unset # roles: unset # level: unset # range: proper superset user test45 roles system level s5:c5 range s5:c5 - s5:c1.c3,c5; ################################################################################ #users user system roles system level s0:c5 range s0:c5; #normal constraints constrain infoflow hi_w (u1 == u2); #isids sid kernel system:system:system:s0:c5 sid security system:system:system:s0:c5 #fs_use fs_use_trans devpts system:object_r:system:s0:c5; fs_use_xattr ext3 system:object_r:system:s0:c5; fs_use_task pipefs system:object_r:system:s0:c5; #genfscon genfscon proc / system:object_r:system:s3 genfscon proc /sys system:object_r:system:s0:c5 genfscon selinuxfs / system:object_r:system:s3:c0.c4 portcon tcp 80 system:object_r:system:s0:c5 netifcon eth0 system:object_r:system:s0:c5 system:object_r:system:s0:c5 nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0:c5 nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0:c5 setools-4.4.0/tests/userquery.py000066400000000000000000000225641402045477700170120ustar00rootroot00000000000000# Copyright 2014-2015, Tresys Technology, LLC # # This file is part of SETools. # # SETools is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # SETools 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 SETools. If not, see . # import os import unittest from setools import UserQuery from .policyrep.util import compile_policy class UserQueryTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.p = compile_policy("tests/userquery.conf") @classmethod def tearDownClass(cls): os.unlink(cls.p.path) def test_000_unset(self): """User query with no criteria.""" # query with no parameters gets all types. allusers = sorted(self.p.users()) q = UserQuery(self.p) qusers = sorted(q.results()) self.assertListEqual(allusers, qusers) def test_001_name_exact(self): """User query with exact name match.""" q = UserQuery(self.p, name="test1_u") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test1_u"], users) def test_002_name_regex(self): """User query with regex name match.""" q = UserQuery(self.p, name="test2_u(1|2)", name_regex=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test2_u1", "test2_u2"], users) def test_010_role_intersect(self): """User query with role set intersection.""" q = UserQuery(self.p, roles=["test10a_r", "test10b_r"]) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test10_u1", "test10_u2", "test10_u3", "test10_u4", "test10_u5", "test10_u6"], users) def test_011_role_equality(self): """User query with role set equality.""" q = UserQuery( self.p, roles=["test11a_r", "test11b_r"], roles_equal=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test11_u2"], users) def test_012_role_regex(self): """User query with role regex match.""" q = UserQuery(self.p, roles="test12(a|b)_r", roles_regex=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test12_u1", "test12_u2", "test12_u3", "test12_u4", "test12_u5", "test12_u6"], users) def test_020_level_equal(self): """User query with default level equality.""" q = UserQuery(self.p, level="s3:c0,c4") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test20"], users) def test_021_level_dom1(self): """User query with default level dominance.""" q = UserQuery(self.p, level="s2:c1,c2,c4", level_dom=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], users) def test_021_level_dom2(self): """User query with default level dominance (equal).""" q = UserQuery(self.p, level="s2:c1,c4", level_dom=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test21"], users) def test_022_level_domby1(self): """User query with default level dominated-by.""" q = UserQuery(self.p, level="s3:c2", level_domby=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], users) def test_022_level_domby2(self): """User query with default level dominated-by (equal).""" q = UserQuery(self.p, level="s3:c2,c4", level_domby=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test22"], users) def test_023_level_incomp(self): """User query with default level icomparable.""" q = UserQuery(self.p, level="s5:c0.c5,c7", level_incomp=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test23"], users) def test_040_range_exact(self): """User query with range exact match""" q = UserQuery(self.p, range_="s0:c5 - s0:c0.c5") users = sorted(str(u) for u in q.results()) self.assertListEqual(["test40"], users) def test_041_range_overlap1(self): """User query with range overlap match (equal)""" q = UserQuery(self.p, range_="s1:c5 - s1:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap2(self): """User query with range overlap match (subset)""" q = UserQuery(self.p, range_="s1:c2,c5 - s1:c2.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap3(self): """User query with range overlap match (superset)""" q = UserQuery(self.p, range_="s1 - s1:c0.c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap4(self): """User query with range overlap match (overlap low level)""" q = UserQuery(self.p, range_="s1:c5 - s1:c2,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_041_range_overlap5(self): """User query with range overlap match (overlap high level)""" q = UserQuery(self.p, range_="s1:c5,c2 - s1:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test41"], users) def test_042_range_subset1(self): """User query with range subset match""" q = UserQuery(self.p, range_="s2:c2,c5 - s2:c2.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test42"], users) def test_042_range_subset2(self): """User query with range subset match (equal)""" q = UserQuery(self.p, range_="s2:c5 - s2:c1.c3,c5", range_overlap=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test42"], users) def test_043_range_superset1(self): """User query with range superset match""" q = UserQuery(self.p, range_="s3 - s3:c0.c6", range_superset=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test43"], users) def test_043_range_superset2(self): """User query with range superset match (equal)""" q = UserQuery(self.p, range_="s3:c5 - s3:c1.c3,c5.c6", range_superset=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test43"], users) def test_044_range_proper_subset1(self): """User query with range proper subset match""" q = UserQuery(self.p, range_="s4:c2,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_044_range_proper_subset2(self): """User query with range proper subset match (equal)""" q = UserQuery(self.p, range_="s4:c5 - s4:c1.c3,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual([], users) def test_044_range_proper_subset3(self): """User query with range proper subset match (equal low)""" q = UserQuery(self.p, range_="s4:c5 - s4:c1.c2,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_044_range_proper_subset4(self): """User query with range proper subset match (equal high)""" q = UserQuery(self.p, range_="s4:c1,c5 - s4:c1.c3,c5", range_subset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test44"], users) def test_045_range_proper_superset1(self): """User query with range proper superset match""" q = UserQuery(self.p, range_="s5 - s5:c0.c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) def test_045_range_proper_superset2(self): """User query with range proper superset match (equal)""" q = UserQuery(self.p, range_="s5:c5 - s5:c1.c3,c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual([], users) def test_045_range_proper_superset3(self): """User query with range proper superset match (equal low)""" q = UserQuery(self.p, range_="s5:c5 - s5:c1.c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) def test_045_range_proper_superset4(self): """User query with range proper superset match (equal high)""" q = UserQuery(self.p, range_="s5 - s5:c1.c3,c5", range_superset=True, range_proper=True) users = sorted(str(u) for u in q.results()) self.assertListEqual(["test45"], users) setools-4.4.0/tox.ini000066400000000000000000000032671402045477700145440ustar00rootroot00000000000000[tox] minversion = 1.4 envlist = py3, pep8, lint, mypy [pycodestyle] max-line-length = 100 [testenv:pep8] deps = {[testenv]deps} pycodestyle commands_pre = pycodestyle --version commands = pycodestyle setools/ setoolsgui/ tests/ seinfo seinfoflow sedta sesearch sediff sechecker apol --statistics [testenv:coverage] setenv = SETOOLS_COVERAGE = 1 deps = {[testenv]deps} coverage>=4.0 commands_pre = coverage --version coverage erase {envpython} setup.py build_ext -i commands = coverage run setup.py test -q coverage report [testenv:lint] deps = {[testenv]deps} pylint commands_pre = pylint --version {envpython} setup.py build_ext -i commands = pylint -E --rcfile .pylintrc setools tests seinfo seinfoflow sedta sesearch sediff sechecker # pylint can't see all members introduced by PyQt uic pylint -E --rcfile .pylintrc --disable=no-member,import-error setoolsgui apol [testenv:mypy] deps = {[testenv]deps} mypy commands_pre = mypy --version commands = mypy -p setools mypy -p setoolsgui mypy seinfo mypy seinfoflow mypy sedta mypy sesearch mypy sediff mypy sechecker mypy apol [testenv] passenv = USERSPACE_SRC deps = networkx==2.0 cython>=0.27 commands_pre = {envpython} setup.py build_ext -i commands = {envpython} setup.py test -q