summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/sepolgen/refparser.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/sepolgen/refparser.py')
-rw-r--r--lib/python2.7/site-packages/sepolgen/refparser.py1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/sepolgen/refparser.py b/lib/python2.7/site-packages/sepolgen/refparser.py
new file mode 100644
index 0000000..9b1d0c8
--- /dev/null
+++ b/lib/python2.7/site-packages/sepolgen/refparser.py
@@ -0,0 +1,1129 @@
+# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
+#
+# Copyright (C) 2006-2007 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# OVERVIEW
+#
+#
+# This is a parser for the refpolicy policy "language" - i.e., the
+# normal SELinux policy language plus the refpolicy style M4 macro
+# constructs on top of that base language. This parser is primarily
+# aimed at parsing the policy headers in order to create an abstract
+# policy representation suitable for generating policy.
+#
+# Both the lexer and parser are included in this file. The are implemented
+# using the Ply library (included with sepolgen).
+
+import sys
+import os
+import re
+import traceback
+
+from . import access
+from . import defaults
+from . import lex
+from . import refpolicy
+from . import yacc
+
+# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+#
+# lexer
+#
+# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+tokens = (
+ # basic tokens, punctuation
+ 'TICK',
+ 'SQUOTE',
+ 'OBRACE',
+ 'CBRACE',
+ 'SEMI',
+ 'COLON',
+ 'OPAREN',
+ 'CPAREN',
+ 'COMMA',
+ 'MINUS',
+ 'TILDE',
+ 'ASTERISK',
+ 'AMP',
+ 'BAR',
+ 'EXPL',
+ 'EQUAL',
+ 'FILENAME',
+ 'IDENTIFIER',
+ 'NUMBER',
+ 'PATH',
+ 'IPV6_ADDR',
+ # reserved words
+ # module
+ 'MODULE',
+ 'POLICY_MODULE',
+ 'REQUIRE',
+ # flask
+ 'SID',
+ 'GENFSCON',
+ 'FS_USE_XATTR',
+ 'FS_USE_TRANS',
+ 'FS_USE_TASK',
+ 'PORTCON',
+ 'NODECON',
+ 'NETIFCON',
+ 'PIRQCON',
+ 'IOMEMCON',
+ 'IOPORTCON',
+ 'PCIDEVICECON',
+ 'DEVICETREECON',
+ # object classes
+ 'CLASS',
+ # types and attributes
+ 'TYPEATTRIBUTE',
+ 'ROLEATTRIBUTE',
+ 'TYPE',
+ 'ATTRIBUTE',
+ 'ATTRIBUTE_ROLE',
+ 'ALIAS',
+ 'TYPEALIAS',
+ # conditional policy
+ 'BOOL',
+ 'TRUE',
+ 'FALSE',
+ 'IF',
+ 'ELSE',
+ # users and roles
+ 'ROLE',
+ 'TYPES',
+ # rules
+ 'ALLOW',
+ 'DONTAUDIT',
+ 'AUDITALLOW',
+ 'NEVERALLOW',
+ 'PERMISSIVE',
+ 'TYPE_TRANSITION',
+ 'TYPE_CHANGE',
+ 'TYPE_MEMBER',
+ 'RANGE_TRANSITION',
+ 'ROLE_TRANSITION',
+ # refpolicy keywords
+ 'OPT_POLICY',
+ 'INTERFACE',
+ 'TUNABLE_POLICY',
+ 'GEN_REQ',
+ 'TEMPLATE',
+ 'GEN_CONTEXT',
+ # m4
+ 'IFELSE',
+ 'IFDEF',
+ 'IFNDEF',
+ 'DEFINE'
+ )
+
+# All reserved keywords - see t_IDENTIFIER for how these are matched in
+# the lexer.
+reserved = {
+ # module
+ 'module' : 'MODULE',
+ 'policy_module' : 'POLICY_MODULE',
+ 'require' : 'REQUIRE',
+ # flask
+ 'sid' : 'SID',
+ 'genfscon' : 'GENFSCON',
+ 'fs_use_xattr' : 'FS_USE_XATTR',
+ 'fs_use_trans' : 'FS_USE_TRANS',
+ 'fs_use_task' : 'FS_USE_TASK',
+ 'portcon' : 'PORTCON',
+ 'nodecon' : 'NODECON',
+ 'netifcon' : 'NETIFCON',
+ 'pirqcon' : 'PIRQCON',
+ 'iomemcon' : 'IOMEMCON',
+ 'ioportcon' : 'IOPORTCON',
+ 'pcidevicecon' : 'PCIDEVICECON',
+ 'devicetreecon' : 'DEVICETREECON',
+ # object classes
+ 'class' : 'CLASS',
+ # types and attributes
+ 'typeattribute' : 'TYPEATTRIBUTE',
+ 'roleattribute' : 'ROLEATTRIBUTE',
+ 'type' : 'TYPE',
+ 'attribute' : 'ATTRIBUTE',
+ 'attribute_role' : 'ATTRIBUTE_ROLE',
+ 'alias' : 'ALIAS',
+ 'typealias' : 'TYPEALIAS',
+ # conditional policy
+ 'bool' : 'BOOL',
+ 'true' : 'TRUE',
+ 'false' : 'FALSE',
+ 'if' : 'IF',
+ 'else' : 'ELSE',
+ # users and roles
+ 'role' : 'ROLE',
+ 'types' : 'TYPES',
+ # rules
+ 'allow' : 'ALLOW',
+ 'dontaudit' : 'DONTAUDIT',
+ 'auditallow' : 'AUDITALLOW',
+ 'neverallow' : 'NEVERALLOW',
+ 'permissive' : 'PERMISSIVE',
+ 'type_transition' : 'TYPE_TRANSITION',
+ 'type_change' : 'TYPE_CHANGE',
+ 'type_member' : 'TYPE_MEMBER',
+ 'range_transition' : 'RANGE_TRANSITION',
+ 'role_transition' : 'ROLE_TRANSITION',
+ # refpolicy keywords
+ 'optional_policy' : 'OPT_POLICY',
+ 'interface' : 'INTERFACE',
+ 'tunable_policy' : 'TUNABLE_POLICY',
+ 'gen_require' : 'GEN_REQ',
+ 'template' : 'TEMPLATE',
+ 'gen_context' : 'GEN_CONTEXT',
+ # M4
+ 'ifelse' : 'IFELSE',
+ 'ifndef' : 'IFNDEF',
+ 'ifdef' : 'IFDEF',
+ 'define' : 'DEFINE'
+ }
+
+# The ply lexer allows definition of tokens in 2 ways: regular expressions
+# or functions.
+
+# Simple regex tokens
+t_TICK = r'\`'
+t_SQUOTE = r'\''
+t_OBRACE = r'\{'
+t_CBRACE = r'\}'
+# This will handle spurios extra ';' via the +
+t_SEMI = r'\;+'
+t_COLON = r'\:'
+t_OPAREN = r'\('
+t_CPAREN = r'\)'
+t_COMMA = r'\,'
+t_MINUS = r'\-'
+t_TILDE = r'\~'
+t_ASTERISK = r'\*'
+t_AMP = r'\&'
+t_BAR = r'\|'
+t_EXPL = r'\!'
+t_EQUAL = r'\='
+t_NUMBER = r'[0-9\.]+'
+t_PATH = r'/[a-zA-Z0-9)_\.\*/\$]*'
+#t_IPV6_ADDR = r'[a-fA-F0-9]{0,4}:[a-fA-F0-9]{0,4}:([a-fA-F0-9]{0,4}:)*'
+
+# Ignore whitespace - this is a special token for ply that more efficiently
+# ignores uninteresting tokens.
+t_ignore = " \t"
+
+# More complex tokens
+def t_IPV6_ADDR(t):
+ r'[a-fA-F0-9]{0,4}:[a-fA-F0-9]{0,4}:([a-fA-F0-9]|:)*'
+ # This is a function simply to force it sooner into
+ # the regex list
+ return t
+
+def t_m4comment(t):
+ r'dnl.*\n'
+ # Ignore all comments
+ t.lexer.lineno += 1
+
+def t_refpolicywarn1(t):
+ r'define.*refpolicywarn\(.*\n'
+ # Ignore refpolicywarn statements - they sometimes
+ # contain text that we can't parse.
+ t.skip(1)
+
+def t_refpolicywarn(t):
+ r'refpolicywarn\(.*\n'
+ # Ignore refpolicywarn statements - they sometimes
+ # contain text that we can't parse.
+ t.lexer.lineno += 1
+
+def t_IDENTIFIER(t):
+ r'[a-zA-Z_\$][a-zA-Z0-9_\-\+\.\$\*~]*'
+ # Handle any keywords
+ t.type = reserved.get(t.value,'IDENTIFIER')
+ return t
+
+def t_FILENAME(t):
+ r'\"[a-zA-Z0-9_\-\+\.\$\*~ :]+\"'
+ # Handle any keywords
+ t.type = reserved.get(t.value,'FILENAME')
+ return t
+
+def t_comment(t):
+ r'\#.*\n'
+ # Ignore all comments
+ t.lexer.lineno += 1
+
+def t_error(t):
+ print("Illegal character '%s'" % t.value[0])
+ t.skip(1)
+
+def t_newline(t):
+ r'\n+'
+ t.lexer.lineno += len(t.value)
+
+# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+#
+# Parser
+#
+# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+# Global data used during parsing - making it global is easier than
+# passing the state through the parsing functions.
+
+# m is the top-level data structure (stands for modules).
+m = None
+# error is either None (indicating no error) or a string error message.
+error = None
+parse_file = ""
+# spt is the support macros (e.g., obj/perm sets) - it is an instance of
+# refpolicy.SupportMacros and should always be present during parsing
+# though it may not contain any macros.
+spt = None
+success = True
+
+# utilities
+def collect(stmts, parent, val=None):
+ if stmts is None:
+ return
+ for s in stmts:
+ if s is None:
+ continue
+ s.parent = parent
+ if val is not None:
+ parent.children.insert(0, (val, s))
+ else:
+ parent.children.insert(0, s)
+
+def expand(ids, s):
+ for id in ids:
+ if spt.has_key(id):
+ s.update(spt.by_name(id))
+ else:
+ s.add(id)
+
+# Top-level non-terminal
+def p_statements(p):
+ '''statements : statement
+ | statements statement
+ | empty
+ '''
+ if len(p) == 2 and p[1]:
+ m.children.append(p[1])
+ elif len(p) > 2 and p[2]:
+ m.children.append(p[2])
+
+def p_statement(p):
+ '''statement : interface
+ | template
+ | obj_perm_set
+ | policy
+ | policy_module_stmt
+ | module_stmt
+ '''
+ p[0] = p[1]
+
+def p_empty(p):
+ 'empty :'
+ pass
+
+#
+# Reference policy language constructs
+#
+
+# This is for the policy module statement (e.g., policy_module(foo,1.2.0)).
+# We have a separate terminal for either the basic language module statement
+# and interface calls to make it easier to identifier.
+def p_policy_module_stmt(p):
+ 'policy_module_stmt : POLICY_MODULE OPAREN IDENTIFIER COMMA NUMBER CPAREN'
+ m = refpolicy.ModuleDeclaration()
+ m.name = p[3]
+ m.version = p[5]
+ m.refpolicy = True
+ p[0] = m
+
+def p_interface(p):
+ '''interface : INTERFACE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ '''
+ x = refpolicy.Interface(p[4])
+ collect(p[8], x)
+ p[0] = x
+
+def p_template(p):
+ '''template : TEMPLATE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ | DEFINE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ '''
+ x = refpolicy.Template(p[4])
+ collect(p[8], x)
+ p[0] = x
+
+def p_define(p):
+ '''define : DEFINE OPAREN TICK IDENTIFIER SQUOTE CPAREN'''
+ # This is for defining single M4 values (to be used later in ifdef statements).
+ # Example: define(`sulogin_no_pam'). We don't currently do anything with these
+ # but we should in the future when we correctly resolve ifdef statements.
+ p[0] = None
+
+def p_interface_stmts(p):
+ '''interface_stmts : policy
+ | interface_stmts policy
+ | empty
+ '''
+ if len(p) == 2 and p[1]:
+ p[0] = p[1]
+ elif len(p) > 2:
+ if not p[1]:
+ if p[2]:
+ p[0] = p[2]
+ elif not p[2]:
+ p[0] = p[1]
+ else:
+ p[0] = p[1] + p[2]
+
+def p_optional_policy(p):
+ '''optional_policy : OPT_POLICY OPAREN TICK interface_stmts SQUOTE CPAREN
+ | OPT_POLICY OPAREN TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ '''
+ o = refpolicy.OptionalPolicy()
+ collect(p[4], o, val=True)
+ if len(p) > 7:
+ collect(p[8], o, val=False)
+ p[0] = [o]
+
+def p_tunable_policy(p):
+ '''tunable_policy : TUNABLE_POLICY OPAREN TICK cond_expr SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ | TUNABLE_POLICY OPAREN TICK cond_expr SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN
+ '''
+ x = refpolicy.TunablePolicy()
+ x.cond_expr = p[4]
+ collect(p[8], x, val=True)
+ if len(p) > 11:
+ collect(p[12], x, val=False)
+ p[0] = [x]
+
+def p_ifelse(p):
+ '''ifelse : IFELSE OPAREN TICK IDENTIFIER SQUOTE COMMA COMMA TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ | IFELSE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ | IFELSE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ '''
+# x = refpolicy.IfDef(p[4])
+# v = True
+# collect(p[8], x, val=v)
+# if len(p) > 12:
+# collect(p[12], x, val=False)
+# p[0] = [x]
+ pass
+
+
+def p_ifdef(p):
+ '''ifdef : IFDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ | IFNDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ | IFDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi
+ '''
+ x = refpolicy.IfDef(p[4])
+ if p[1] == 'ifdef':
+ v = True
+ else:
+ v = False
+ collect(p[8], x, val=v)
+ if len(p) > 12:
+ collect(p[12], x, val=False)
+ p[0] = [x]
+
+def p_interface_call(p):
+ '''interface_call : IDENTIFIER OPAREN interface_call_param_list CPAREN
+ | IDENTIFIER OPAREN CPAREN
+ | IDENTIFIER OPAREN interface_call_param_list CPAREN SEMI'''
+ # Allow spurious semi-colons at the end of interface calls
+ i = refpolicy.InterfaceCall(ifname=p[1])
+ if len(p) > 4:
+ i.args.extend(p[3])
+ p[0] = i
+
+def p_interface_call_param(p):
+ '''interface_call_param : IDENTIFIER
+ | IDENTIFIER MINUS IDENTIFIER
+ | nested_id_set
+ | TRUE
+ | FALSE
+ | FILENAME
+ '''
+ # Intentionally let single identifiers pass through
+ # List means set, non-list identifier
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = [p[1], "-" + p[3]]
+
+def p_interface_call_param_list(p):
+ '''interface_call_param_list : interface_call_param
+ | interface_call_param_list COMMA interface_call_param
+ '''
+ if len(p) == 2:
+ p[0] = [p[1]]
+ else:
+ p[0] = p[1] + [p[3]]
+
+
+def p_obj_perm_set(p):
+ 'obj_perm_set : DEFINE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK names SQUOTE CPAREN'
+ s = refpolicy.ObjPermSet(p[4])
+ s.perms = p[8]
+ p[0] = s
+
+#
+# Basic SELinux policy language
+#
+
+def p_policy(p):
+ '''policy : policy_stmt
+ | optional_policy
+ | tunable_policy
+ | ifdef
+ | ifelse
+ | conditional
+ '''
+ p[0] = p[1]
+
+def p_policy_stmt(p):
+ '''policy_stmt : gen_require
+ | avrule_def
+ | typerule_def
+ | typeattribute_def
+ | roleattribute_def
+ | interface_call
+ | role_def
+ | role_allow
+ | permissive
+ | type_def
+ | typealias_def
+ | attribute_def
+ | attribute_role_def
+ | range_transition_def
+ | role_transition_def
+ | bool
+ | define
+ | initial_sid
+ | genfscon
+ | fs_use
+ | portcon
+ | nodecon
+ | netifcon
+ | pirqcon
+ | iomemcon
+ | ioportcon
+ | pcidevicecon
+ | devicetreecon
+ '''
+ if p[1]:
+ p[0] = [p[1]]
+
+def p_module_stmt(p):
+ 'module_stmt : MODULE IDENTIFIER NUMBER SEMI'
+ m = refpolicy.ModuleDeclaration()
+ m.name = p[2]
+ m.version = p[3]
+ m.refpolicy = False
+ p[0] = m
+
+def p_gen_require(p):
+ '''gen_require : GEN_REQ OPAREN TICK requires SQUOTE CPAREN
+ | REQUIRE OBRACE requires CBRACE'''
+ # We ignore the require statements - they are redundant data from our point-of-view.
+ # Checkmodule will verify them later anyway so we just assume that they match what
+ # is in the rest of the interface.
+ pass
+
+def p_requires(p):
+ '''requires : require
+ | requires require
+ | ifdef
+ | requires ifdef
+ '''
+ pass
+
+def p_require(p):
+ '''require : TYPE comma_list SEMI
+ | ROLE comma_list SEMI
+ | ATTRIBUTE comma_list SEMI
+ | ATTRIBUTE_ROLE comma_list SEMI
+ | CLASS comma_list SEMI
+ | BOOL comma_list SEMI
+ '''
+ pass
+
+def p_security_context(p):
+ '''security_context : IDENTIFIER COLON IDENTIFIER COLON IDENTIFIER
+ | IDENTIFIER COLON IDENTIFIER COLON IDENTIFIER COLON mls_range_def'''
+ # This will likely need some updates to handle complex levels
+ s = refpolicy.SecurityContext()
+ s.user = p[1]
+ s.role = p[3]
+ s.type = p[5]
+ if len(p) > 6:
+ s.level = p[7]
+
+ p[0] = s
+
+def p_gen_context(p):
+ '''gen_context : GEN_CONTEXT OPAREN security_context COMMA mls_range_def CPAREN
+ '''
+ # We actually store gen_context statements in a SecurityContext
+ # object - it knows how to output either a bare context or a
+ # gen_context statement.
+ s = p[3]
+ s.level = p[5]
+
+ p[0] = s
+
+def p_context(p):
+ '''context : security_context
+ | gen_context
+ '''
+ p[0] = p[1]
+
+def p_initial_sid(p):
+ '''initial_sid : SID IDENTIFIER context'''
+ s = refpolicy.InitialSid()
+ s.name = p[2]
+ s.context = p[3]
+ p[0] = s
+
+def p_genfscon(p):
+ '''genfscon : GENFSCON IDENTIFIER PATH context'''
+
+ g = refpolicy.GenfsCon()
+ g.filesystem = p[2]
+ g.path = p[3]
+ g.context = p[4]
+
+ p[0] = g
+
+def p_fs_use(p):
+ '''fs_use : FS_USE_XATTR IDENTIFIER context SEMI
+ | FS_USE_TASK IDENTIFIER context SEMI
+ | FS_USE_TRANS IDENTIFIER context SEMI
+ '''
+ f = refpolicy.FilesystemUse()
+ if p[1] == "fs_use_xattr":
+ f.type = refpolicy.FilesystemUse.XATTR
+ elif p[1] == "fs_use_task":
+ f.type = refpolicy.FilesystemUse.TASK
+ elif p[1] == "fs_use_trans":
+ f.type = refpolicy.FilesystemUse.TRANS
+
+ f.filesystem = p[2]
+ f.context = p[3]
+
+ p[0] = f
+
+def p_portcon(p):
+ '''portcon : PORTCON IDENTIFIER NUMBER context
+ | PORTCON IDENTIFIER NUMBER MINUS NUMBER context'''
+ c = refpolicy.PortCon()
+ c.port_type = p[2]
+ if len(p) == 5:
+ c.port_number = p[3]
+ c.context = p[4]
+ else:
+ c.port_number = p[3] + "-" + p[4]
+ c.context = p[5]
+
+ p[0] = c
+
+def p_nodecon(p):
+ '''nodecon : NODECON NUMBER NUMBER context
+ | NODECON IPV6_ADDR IPV6_ADDR context
+ '''
+ n = refpolicy.NodeCon()
+ n.start = p[2]
+ n.end = p[3]
+ n.context = p[4]
+
+ p[0] = n
+
+def p_netifcon(p):
+ 'netifcon : NETIFCON IDENTIFIER context context'
+ n = refpolicy.NetifCon()
+ n.interface = p[2]
+ n.interface_context = p[3]
+ n.packet_context = p[4]
+
+ p[0] = n
+
+def p_pirqcon(p):
+ 'pirqcon : PIRQCON NUMBER context'
+ c = refpolicy.PirqCon()
+ c.pirq_number = p[2]
+ c.context = p[3]
+
+ p[0] = c
+
+def p_iomemcon(p):
+ '''iomemcon : IOMEMCON NUMBER context
+ | IOMEMCON NUMBER MINUS NUMBER context'''
+ c = refpolicy.IomemCon()
+ if len(p) == 4:
+ c.device_mem = p[2]
+ c.context = p[3]
+ else:
+ c.device_mem = p[2] + "-" + p[3]
+ c.context = p[4]
+
+ p[0] = c
+
+def p_ioportcon(p):
+ '''ioportcon : IOPORTCON NUMBER context
+ | IOPORTCON NUMBER MINUS NUMBER context'''
+ c = refpolicy.IoportCon()
+ if len(p) == 4:
+ c.ioport = p[2]
+ c.context = p[3]
+ else:
+ c.ioport = p[2] + "-" + p[3]
+ c.context = p[4]
+
+ p[0] = c
+
+def p_pcidevicecon(p):
+ 'pcidevicecon : PCIDEVICECON NUMBER context'
+ c = refpolicy.PciDeviceCon()
+ c.device = p[2]
+ c.context = p[3]
+
+ p[0] = c
+
+def p_devicetreecon(p):
+ 'devicetreecon : DEVICETREECON NUMBER context'
+ c = refpolicy.DevicetTeeCon()
+ c.path = p[2]
+ c.context = p[3]
+
+ p[0] = c
+
+def p_mls_range_def(p):
+ '''mls_range_def : mls_level_def MINUS mls_level_def
+ | mls_level_def
+ '''
+ p[0] = p[1]
+ if len(p) > 2:
+ p[0] = p[0] + "-" + p[3]
+
+def p_mls_level_def(p):
+ '''mls_level_def : IDENTIFIER COLON comma_list
+ | IDENTIFIER
+ '''
+ p[0] = p[1]
+ if len(p) > 2:
+ p[0] = p[0] + ":" + ",".join(p[3])
+
+def p_type_def(p):
+ '''type_def : TYPE IDENTIFIER COMMA comma_list SEMI
+ | TYPE IDENTIFIER SEMI
+ | TYPE IDENTIFIER ALIAS names SEMI
+ | TYPE IDENTIFIER ALIAS names COMMA comma_list SEMI
+ '''
+ t = refpolicy.Type(p[2])
+ if len(p) == 6:
+ if p[3] == ',':
+ t.attributes.update(p[4])
+ else:
+ t.aliases = p[4]
+ elif len(p) > 4:
+ t.aliases = p[4]
+ if len(p) == 8:
+ t.attributes.update(p[6])
+ p[0] = t
+
+def p_attribute_def(p):
+ 'attribute_def : ATTRIBUTE IDENTIFIER SEMI'
+ a = refpolicy.Attribute(p[2])
+ p[0] = a
+
+def p_attribute_role_def(p):
+ 'attribute_role_def : ATTRIBUTE_ROLE IDENTIFIER SEMI'
+ a = refpolicy.Attribute_Role(p[2])
+ p[0] = a
+
+def p_typealias_def(p):
+ 'typealias_def : TYPEALIAS IDENTIFIER ALIAS names SEMI'
+ t = refpolicy.TypeAlias()
+ t.type = p[2]
+ t.aliases = p[4]
+ p[0] = t
+
+def p_role_def(p):
+ '''role_def : ROLE IDENTIFIER TYPES comma_list SEMI
+ | ROLE IDENTIFIER SEMI'''
+ r = refpolicy.Role()
+ r.role = p[2]
+ if len(p) > 4:
+ r.types.update(p[4])
+ p[0] = r
+
+def p_role_allow(p):
+ 'role_allow : ALLOW names names SEMI'
+ r = refpolicy.RoleAllow()
+ r.src_roles = p[2]
+ r.tgt_roles = p[3]
+ p[0] = r
+
+def p_permissive(p):
+ 'permissive : PERMISSIVE names SEMI'
+ t.skip(1)
+
+def p_avrule_def(p):
+ '''avrule_def : ALLOW names names COLON names names SEMI
+ | DONTAUDIT names names COLON names names SEMI
+ | AUDITALLOW names names COLON names names SEMI
+ | NEVERALLOW names names COLON names names SEMI
+ '''
+ a = refpolicy.AVRule()
+ if p[1] == 'dontaudit':
+ a.rule_type = refpolicy.AVRule.DONTAUDIT
+ elif p[1] == 'auditallow':
+ a.rule_type = refpolicy.AVRule.AUDITALLOW
+ elif p[1] == 'neverallow':
+ a.rule_type = refpolicy.AVRule.NEVERALLOW
+ a.src_types = p[2]
+ a.tgt_types = p[3]
+ a.obj_classes = p[5]
+ a.perms = p[6]
+ p[0] = a
+
+def p_typerule_def(p):
+ '''typerule_def : TYPE_TRANSITION names names COLON names IDENTIFIER SEMI
+ | TYPE_TRANSITION names names COLON names IDENTIFIER FILENAME SEMI
+ | TYPE_TRANSITION names names COLON names IDENTIFIER IDENTIFIER SEMI
+ | TYPE_CHANGE names names COLON names IDENTIFIER SEMI
+ | TYPE_MEMBER names names COLON names IDENTIFIER SEMI
+ '''
+ t = refpolicy.TypeRule()
+ if p[1] == 'type_change':
+ t.rule_type = refpolicy.TypeRule.TYPE_CHANGE
+ elif p[1] == 'type_member':
+ t.rule_type = refpolicy.TypeRule.TYPE_MEMBER
+ t.src_types = p[2]
+ t.tgt_types = p[3]
+ t.obj_classes = p[5]
+ t.dest_type = p[6]
+ t.file_name = p[7]
+ p[0] = t
+
+def p_bool(p):
+ '''bool : BOOL IDENTIFIER TRUE SEMI
+ | BOOL IDENTIFIER FALSE SEMI'''
+ b = refpolicy.Bool()
+ b.name = p[2]
+ if p[3] == "true":
+ b.state = True
+ else:
+ b.state = False
+ p[0] = b
+
+def p_conditional(p):
+ ''' conditional : IF OPAREN cond_expr CPAREN OBRACE interface_stmts CBRACE
+ | IF OPAREN cond_expr CPAREN OBRACE interface_stmts CBRACE ELSE OBRACE interface_stmts CBRACE
+ '''
+ c = refpolicy.Conditional()
+ c.cond_expr = p[3]
+ collect(p[6], c, val=True)
+ if len(p) > 8:
+ collect(p[10], c, val=False)
+ p[0] = [c]
+
+def p_typeattribute_def(p):
+ '''typeattribute_def : TYPEATTRIBUTE IDENTIFIER comma_list SEMI'''
+ t = refpolicy.TypeAttribute()
+ t.type = p[2]
+ t.attributes.update(p[3])
+ p[0] = t
+
+def p_roleattribute_def(p):
+ '''roleattribute_def : ROLEATTRIBUTE IDENTIFIER comma_list SEMI'''
+ t = refpolicy.RoleAttribute()
+ t.role = p[2]
+ t.roleattributes.update(p[3])
+ p[0] = t
+
+def p_range_transition_def(p):
+ '''range_transition_def : RANGE_TRANSITION names names COLON names mls_range_def SEMI
+ | RANGE_TRANSITION names names names SEMI'''
+ pass
+
+def p_role_transition_def(p):
+ '''role_transition_def : ROLE_TRANSITION names names names SEMI'''
+ pass
+
+def p_cond_expr(p):
+ '''cond_expr : IDENTIFIER
+ | EXPL cond_expr
+ | cond_expr AMP AMP cond_expr
+ | cond_expr BAR BAR cond_expr
+ | cond_expr EQUAL EQUAL cond_expr
+ | cond_expr EXPL EQUAL cond_expr
+ '''
+ l = len(p)
+ if l == 2:
+ p[0] = [p[1]]
+ elif l == 3:
+ p[0] = [p[1]] + p[2]
+ else:
+ p[0] = p[1] + [p[2] + p[3]] + p[4]
+
+
+#
+# Basic terminals
+#
+
+# Identifiers and lists of identifiers. These must
+# be handled somewhat gracefully. Names returns an IdSet and care must
+# be taken that this is _assigned_ to an object to correctly update
+# all of the flags (as opposed to using update). The other terminals
+# return list - this is to preserve ordering if it is important for
+# parsing (for example, interface_call must retain the ordering). Other
+# times the list should be used to update an IdSet.
+
+def p_names(p):
+ '''names : identifier
+ | nested_id_set
+ | asterisk
+ | TILDE identifier
+ | TILDE nested_id_set
+ | IDENTIFIER MINUS IDENTIFIER
+ '''
+ s = refpolicy.IdSet()
+ if len(p) < 3:
+ expand(p[1], s)
+ elif len(p) == 3:
+ expand(p[2], s)
+ s.compliment = True
+ else:
+ expand([p[1]])
+ s.add("-" + p[3])
+ p[0] = s
+
+def p_identifier(p):
+ 'identifier : IDENTIFIER'
+ p[0] = [p[1]]
+
+def p_asterisk(p):
+ 'asterisk : ASTERISK'
+ p[0] = [p[1]]
+
+def p_nested_id_set(p):
+ '''nested_id_set : OBRACE nested_id_list CBRACE
+ '''
+ p[0] = p[2]
+
+def p_nested_id_list(p):
+ '''nested_id_list : nested_id_element
+ | nested_id_list nested_id_element
+ '''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ p[0] = p[1] + p[2]
+
+def p_nested_id_element(p):
+ '''nested_id_element : identifier
+ | MINUS IDENTIFIER
+ | nested_id_set
+ '''
+ if len(p) == 2:
+ p[0] = p[1]
+ else:
+ # For now just leave the '-'
+ str = "-" + p[2]
+ p[0] = [str]
+
+def p_comma_list(p):
+ '''comma_list : nested_id_list
+ | comma_list COMMA nested_id_list
+ '''
+ if len(p) > 2:
+ p[1] = p[1] + p[3]
+ p[0] = p[1]
+
+def p_optional_semi(p):
+ '''optional_semi : SEMI
+ | empty'''
+ pass
+
+
+#
+# Interface to the parser
+#
+
+def p_error(tok):
+ global error, parse_file, success, parser
+ error = "%s: Syntax error on line %d %s [type=%s]" % (parse_file, tok.lineno, tok.value, tok.type)
+ print(error)
+ success = False
+
+def prep_spt(spt):
+ if not spt:
+ return { }
+ map = {}
+ for x in spt:
+ map[x.name] = x
+
+parser = None
+lexer = None
+def create_globals(module, support, debug):
+ global parser, lexer, m, spt
+
+ if not parser:
+ lexer = lex.lex()
+ parser = yacc.yacc(method="LALR", debug=debug, write_tables=0)
+
+ if module is not None:
+ m = module
+ else:
+ m = refpolicy.Module()
+
+ if not support:
+ spt = refpolicy.SupportMacros()
+ else:
+ spt = support
+
+def parse(text, module=None, support=None, debug=False):
+ create_globals(module, support, debug)
+ global error, parser, lexer, success
+
+ lexer.lineno = 1
+ success = True
+
+ try:
+ parser.parse(text, debug=debug, lexer=lexer)
+ except Exception as e:
+ parser = None
+ lexer = None
+ error = "internal parser error: %s" % str(e) + "\n" + traceback.format_exc()
+
+ if not success:
+ # force the parser and lexer to be rebuilt - we have some problems otherwise
+ parser = None
+ msg = 'could not parse text: "%s"' % error
+ raise ValueError(msg)
+ return m
+
+def list_headers(root):
+ modules = []
+ support_macros = None
+
+ for dirpath, dirnames, filenames in os.walk(root):
+ for name in filenames:
+ modname = os.path.splitext(name)
+ filename = os.path.join(dirpath, name)
+
+ if modname[1] == '.spt':
+ if name == "obj_perm_sets.spt":
+ support_macros = filename
+ elif len(re.findall("patterns", modname[0])):
+ modules.append((modname[0], filename))
+ elif modname[1] == '.if':
+ modules.append((modname[0], filename))
+
+ return (modules, support_macros)
+
+
+def parse_headers(root, output=None, expand=True, debug=False):
+ from . import util
+
+ headers = refpolicy.Headers()
+
+ modules = []
+ support_macros = None
+
+ if os.path.isfile(root):
+ name = os.path.split(root)[1]
+ if name == '':
+ raise ValueError("Invalid file name %s" % root)
+ modname = os.path.splitext(name)
+ modules.append((modname[0], root))
+ all_modules, support_macros = list_headers(defaults.headers())
+ else:
+ modules, support_macros = list_headers(root)
+
+ if expand and not support_macros:
+ raise ValueError("could not find support macros (obj_perm_sets.spt)")
+
+ def o(msg):
+ if output:
+ output.write(msg)
+
+ def parse_file(f, module, spt=None):
+ global parse_file
+ if debug:
+ o("parsing file %s\n" % f)
+ try:
+ fd = open(f)
+ txt = fd.read()
+ fd.close()
+ parse_file = f
+ parse(txt, module, spt, debug)
+ except IOError as e:
+ return
+ except ValueError as e:
+ raise ValueError("error parsing file %s: %s" % (f, str(e)))
+
+ spt = None
+ if support_macros:
+ o("Parsing support macros (%s): " % support_macros)
+ spt = refpolicy.SupportMacros()
+ parse_file(support_macros, spt)
+
+ headers.children.append(spt)
+
+ # FIXME: Total hack - add in can_exec rather than parse the insanity
+ # of misc_macros. We are just going to pretend that this is an interface
+ # to make the expansion work correctly.
+ can_exec = refpolicy.Interface("can_exec")
+ av = access.AccessVector(["$1","$2","file","execute_no_trans","open", "read",
+ "getattr","lock","execute","ioctl"])
+
+ can_exec.children.append(refpolicy.AVRule(av))
+ headers.children.append(can_exec)
+
+ o("done.\n")
+
+ if output and not debug:
+ status = util.ConsoleProgressBar(sys.stdout, steps=len(modules))
+ status.start("Parsing interface files")
+
+ failures = []
+ for x in modules:
+ m = refpolicy.Module()
+ m.name = x[0]
+ try:
+ if expand:
+ parse_file(x[1], m, spt)
+ else:
+ parse_file(x[1], m)
+ except ValueError as e:
+ o(str(e) + "\n")
+ failures.append(x[1])
+ continue
+
+ headers.children.append(m)
+ if output and not debug:
+ status.step()
+
+ if len(failures):
+ o("failed to parse some headers: %s" % ", ".join(failures))
+
+ return headers