| 1 |
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com> |
|---|
| 2 |
# |
|---|
| 3 |
# Copyright (C) 2006-2007 Red Hat |
|---|
| 4 |
# see file 'COPYING' for use and warranty information |
|---|
| 5 |
# |
|---|
| 6 |
# This program is free software; you can redistribute it and/or |
|---|
| 7 |
# modify it under the terms of the GNU General Public License as |
|---|
| 8 |
# published by the Free Software Foundation; version 2 only |
|---|
| 9 |
# |
|---|
| 10 |
# This program is distributed in the hope that it will be useful, |
|---|
| 11 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 |
# GNU General Public License for more details. |
|---|
| 14 |
# |
|---|
| 15 |
# You should have received a copy of the GNU General Public License |
|---|
| 16 |
# along with this program; if not, write to the Free Software |
|---|
| 17 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 |
# |
|---|
| 19 |
|
|---|
| 20 |
# OVERVIEW |
|---|
| 21 |
# |
|---|
| 22 |
# |
|---|
| 23 |
# This is a parser for the refpolicy policy "language" - i.e., the |
|---|
| 24 |
# normal SELinux policy language plus the refpolicy style M4 macro |
|---|
| 25 |
# constructs on top of that base language. This parser is primarily |
|---|
| 26 |
# aimed at parsing the policy headers in order to create an abstract |
|---|
| 27 |
# policy representation suitable for generating policy. |
|---|
| 28 |
# |
|---|
| 29 |
# Both the lexer and parser are included in this file. The are implemented |
|---|
| 30 |
# using the Ply library (included with sepolgen). |
|---|
| 31 |
|
|---|
| 32 |
import sys |
|---|
| 33 |
import os |
|---|
| 34 |
import re |
|---|
| 35 |
import traceback |
|---|
| 36 |
|
|---|
| 37 |
import refpolicy |
|---|
| 38 |
import access |
|---|
| 39 |
import defaults |
|---|
| 40 |
|
|---|
| 41 |
import lex |
|---|
| 42 |
import yacc |
|---|
| 43 |
|
|---|
| 44 |
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
|---|
| 45 |
# |
|---|
| 46 |
# lexer |
|---|
| 47 |
# |
|---|
| 48 |
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
|---|
| 49 |
|
|---|
| 50 |
tokens = ( |
|---|
| 51 |
# basic tokens, punctuation |
|---|
| 52 |
'TICK', |
|---|
| 53 |
'SQUOTE', |
|---|
| 54 |
'OBRACE', |
|---|
| 55 |
'CBRACE', |
|---|
| 56 |
'SEMI', |
|---|
| 57 |
'COLON', |
|---|
| 58 |
'OPAREN', |
|---|
| 59 |
'CPAREN', |
|---|
| 60 |
'COMMA', |
|---|
| 61 |
'MINUS', |
|---|
| 62 |
'TILDE', |
|---|
| 63 |
'ASTERISK', |
|---|
| 64 |
'AMP', |
|---|
| 65 |
'BAR', |
|---|
| 66 |
'EXPL', |
|---|
| 67 |
'EQUAL', |
|---|
| 68 |
'IDENTIFIER', |
|---|
| 69 |
'NUMBER', |
|---|
| 70 |
'PATH', |
|---|
| 71 |
'IPV6_ADDR', |
|---|
| 72 |
# reserved words |
|---|
| 73 |
# module |
|---|
| 74 |
'MODULE', |
|---|
| 75 |
'POLICY_MODULE', |
|---|
| 76 |
'REQUIRE', |
|---|
| 77 |
# flask |
|---|
| 78 |
'SID', |
|---|
| 79 |
'GENFSCON', |
|---|
| 80 |
'FS_USE_XATTR', |
|---|
| 81 |
'FS_USE_TRANS', |
|---|
| 82 |
'FS_USE_TASK', |
|---|
| 83 |
'PORTCON', |
|---|
| 84 |
'NODECON', |
|---|
| 85 |
'NETIFCON', |
|---|
| 86 |
'PIRQCON', |
|---|
| 87 |
'IOMEMCON', |
|---|
| 88 |
'IOPORTCON', |
|---|
| 89 |
'PCIDEVICECON', |
|---|
| 90 |
# object classes |
|---|
| 91 |
'CLASS', |
|---|
| 92 |
# types and attributes |
|---|
| 93 |
'TYPEATTRIBUTE', |
|---|
| 94 |
'TYPE', |
|---|
| 95 |
'ATTRIBUTE', |
|---|
| 96 |
'ALIAS', |
|---|
| 97 |
'TYPEALIAS', |
|---|
| 98 |
# conditional policy |
|---|
| 99 |
'BOOL', |
|---|
| 100 |
'TRUE', |
|---|
| 101 |
'FALSE', |
|---|
| 102 |
'IF', |
|---|
| 103 |
'ELSE', |
|---|
| 104 |
# users and roles |
|---|
| 105 |
'ROLE', |
|---|
| 106 |
'TYPES', |
|---|
| 107 |
# rules |
|---|
| 108 |
'ALLOW', |
|---|
| 109 |
'DONTAUDIT', |
|---|
| 110 |
'AUDITALLOW', |
|---|
| 111 |
'NEVERALLOW', |
|---|
| 112 |
'PERMISSIVE', |
|---|
| 113 |
'TYPE_TRANSITION', |
|---|
| 114 |
'TYPE_CHANGE', |
|---|
| 115 |
'TYPE_MEMBER', |
|---|
| 116 |
'RANGE_TRANSITION', |
|---|
| 117 |
'ROLE_TRANSITION', |
|---|
| 118 |
# refpolicy keywords |
|---|
| 119 |
'OPT_POLICY', |
|---|
| 120 |
'INTERFACE', |
|---|
| 121 |
'TUNABLE_POLICY', |
|---|
| 122 |
'GEN_REQ', |
|---|
| 123 |
'TEMPLATE', |
|---|
| 124 |
'GEN_CONTEXT', |
|---|
| 125 |
# m4 |
|---|
| 126 |
'IFELSE', |
|---|
| 127 |
'IFDEF', |
|---|
| 128 |
'IFNDEF', |
|---|
| 129 |
'DEFINE' |
|---|
| 130 |
) |
|---|
| 131 |
|
|---|
| 132 |
# All reserved keywords - see t_IDENTIFIER for how these are matched in |
|---|
| 133 |
# the lexer. |
|---|
| 134 |
reserved = { |
|---|
| 135 |
# module |
|---|
| 136 |
'module' : 'MODULE', |
|---|
| 137 |
'policy_module' : 'POLICY_MODULE', |
|---|
| 138 |
'require' : 'REQUIRE', |
|---|
| 139 |
# flask |
|---|
| 140 |
'sid' : 'SID', |
|---|
| 141 |
'genfscon' : 'GENFSCON', |
|---|
| 142 |
'fs_use_xattr' : 'FS_USE_XATTR', |
|---|
| 143 |
'fs_use_trans' : 'FS_USE_TRANS', |
|---|
| 144 |
'fs_use_task' : 'FS_USE_TASK', |
|---|
| 145 |
'portcon' : 'PORTCON', |
|---|
| 146 |
'nodecon' : 'NODECON', |
|---|
| 147 |
'netifcon' : 'NETIFCON', |
|---|
| 148 |
'pirqcon' : 'PIRQCON', |
|---|
| 149 |
'iomemcon' : 'IOMEMCON', |
|---|
| 150 |
'ioportcon' : 'IOPORTCON', |
|---|
| 151 |
'pcidevicecon' : 'PCIDEVICECON', |
|---|
| 152 |
# object classes |
|---|
| 153 |
'class' : 'CLASS', |
|---|
| 154 |
# types and attributes |
|---|
| 155 |
'typeattribute' : 'TYPEATTRIBUTE', |
|---|
| 156 |
'type' : 'TYPE', |
|---|
| 157 |
'attribute' : 'ATTRIBUTE', |
|---|
| 158 |
'alias' : 'ALIAS', |
|---|
| 159 |
'typealias' : 'TYPEALIAS', |
|---|
| 160 |
# conditional policy |
|---|
| 161 |
'bool' : 'BOOL', |
|---|
| 162 |
'true' : 'TRUE', |
|---|
| 163 |
'false' : 'FALSE', |
|---|
| 164 |
'if' : 'IF', |
|---|
| 165 |
'else' : 'ELSE', |
|---|
| 166 |
# users and roles |
|---|
| 167 |
'role' : 'ROLE', |
|---|
| 168 |
'types' : 'TYPES', |
|---|
| 169 |
# rules |
|---|
| 170 |
'allow' : 'ALLOW', |
|---|
| 171 |
'dontaudit' : 'DONTAUDIT', |
|---|
| 172 |
'auditallow' : 'AUDITALLOW', |
|---|
| 173 |
'neverallow' : 'NEVERALLOW', |
|---|
| 174 |
'permissive' : 'PERMISSIVE', |
|---|
| 175 |
'type_transition' : 'TYPE_TRANSITION', |
|---|
| 176 |
'type_change' : 'TYPE_CHANGE', |
|---|
| 177 |
'type_member' : 'TYPE_MEMBER', |
|---|
| 178 |
'range_transition' : 'RANGE_TRANSITION', |
|---|
| 179 |
'role_transition' : 'ROLE_TRANSITION', |
|---|
| 180 |
# refpolicy keywords |
|---|
| 181 |
'optional_policy' : 'OPT_POLICY', |
|---|
| 182 |
'interface' : 'INTERFACE', |
|---|
| 183 |
'tunable_policy' : 'TUNABLE_POLICY', |
|---|
| 184 |
'gen_require' : 'GEN_REQ', |
|---|
| 185 |
'template' : 'TEMPLATE', |
|---|
| 186 |
'gen_context' : 'GEN_CONTEXT', |
|---|
| 187 |
# M4 |
|---|
| 188 |
'ifelse' : 'IFELSE', |
|---|
| 189 |
'ifndef' : 'IFNDEF', |
|---|
| 190 |
'ifdef' : 'IFDEF', |
|---|
| 191 |
'define' : 'DEFINE' |
|---|
| 192 |
} |
|---|
| 193 |
|
|---|
| 194 |
# The ply lexer allows definition of tokens in 2 ways: regular expressions |
|---|
| 195 |
# or functions. |
|---|
| 196 |
|
|---|
| 197 |
# Simple regex tokens |
|---|
| 198 |
t_TICK = r'\`' |
|---|
| 199 |
t_SQUOTE = r'\'' |
|---|
| 200 |
t_OBRACE = r'\{' |
|---|
| 201 |
t_CBRACE = r'\}' |
|---|
| 202 |
# This will handle spurios extra ';' via the + |
|---|
| 203 |
t_SEMI = r'\;+' |
|---|
| 204 |
t_COLON = r'\:' |
|---|
| 205 |
t_OPAREN = r'\(' |
|---|
| 206 |
t_CPAREN = r'\)' |
|---|
| 207 |
t_COMMA = r'\,' |
|---|
| 208 |
t_MINUS = r'\-' |
|---|
| 209 |
t_TILDE = r'\~' |
|---|
| 210 |
t_ASTERISK = r'\*' |
|---|
| 211 |
t_AMP = r'\&' |
|---|
| 212 |
t_BAR = r'\|' |
|---|
| 213 |
t_EXPL = r'\!' |
|---|
| 214 |
t_EQUAL = r'\=' |
|---|
| 215 |
t_NUMBER = r'[0-9\.]+' |
|---|
| 216 |
t_PATH = r'/[a-zA-Z0-9)_\.\*/]*' |
|---|
| 217 |
#t_IPV6_ADDR = r'[a-fA-F0-9]{0,4}:[a-fA-F0-9]{0,4}:([a-fA-F0-9]{0,4}:)*' |
|---|
| 218 |
|
|---|
| 219 |
# Ignore whitespace - this is a special token for ply that more efficiently |
|---|
| 220 |
# ignores uninteresting tokens. |
|---|
| 221 |
t_ignore = " \t" |
|---|
| 222 |
|
|---|
| 223 |
# More complex tokens |
|---|
| 224 |
def t_IPV6_ADDR(t): |
|---|
| 225 |
r'[a-fA-F0-9]{0,4}:[a-fA-F0-9]{0,4}:([a-fA-F0-9]|:)*' |
|---|
| 226 |
# This is a function simply to force it sooner into |
|---|
| 227 |
# the regex list |
|---|
| 228 |
return t |
|---|
| 229 |
|
|---|
| 230 |
def t_m4comment(t): |
|---|
| 231 |
r'dnl.*\n' |
|---|
| 232 |
# Ignore all comments |
|---|
| 233 |
t.lexer.lineno += 1 |
|---|
| 234 |
|
|---|
| 235 |
def t_refpolicywarn1(t): |
|---|
| 236 |
r'define.*refpolicywarn\(.*\n' |
|---|
| 237 |
# Ignore refpolicywarn statements - they sometimes |
|---|
| 238 |
# contain text that we can't parse. |
|---|
| 239 |
t.skip(1) |
|---|
| 240 |
|
|---|
| 241 |
def t_refpolicywarn(t): |
|---|
| 242 |
r'refpolicywarn\(.*\n' |
|---|
| 243 |
# Ignore refpolicywarn statements - they sometimes |
|---|
| 244 |
# contain text that we can't parse. |
|---|
| 245 |
t.lexer.lineno += 1 |
|---|
| 246 |
|
|---|
| 247 |
def t_IDENTIFIER(t): |
|---|
| 248 |
r'[a-zA-Z_\$\"][a-zA-Z0-9_\-\.\$\*\"~]*' |
|---|
| 249 |
# Handle any keywords |
|---|
| 250 |
t.type = reserved.get(t.value,'IDENTIFIER') |
|---|
| 251 |
return t |
|---|
| 252 |
|
|---|
| 253 |
def t_comment(t): |
|---|
| 254 |
r'\#.*\n' |
|---|
| 255 |
# Ignore all comments |
|---|
| 256 |
t.lexer.lineno += 1 |
|---|
| 257 |
|
|---|
| 258 |
def t_error(t): |
|---|
| 259 |
print "Illegal character '%s'" % t.value[0] |
|---|
| 260 |
t.skip(1) |
|---|
| 261 |
|
|---|
| 262 |
def t_newline(t): |
|---|
| 263 |
r'\n+' |
|---|
| 264 |
t.lexer.lineno += len(t.value) |
|---|
| 265 |
|
|---|
| 266 |
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
|---|
| 267 |
# |
|---|
| 268 |
# Parser |
|---|
| 269 |
# |
|---|
| 270 |
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
|---|
| 271 |
|
|---|
| 272 |
# Global data used during parsing - making it global is easier than |
|---|
| 273 |
# passing the state through the parsing functions. |
|---|
| 274 |
|
|---|
| 275 |
# m is the top-level data structure (stands for modules). |
|---|
| 276 |
m = None |
|---|
| 277 |
# error is either None (indicating no error) or a string error message. |
|---|
| 278 |
error = None |
|---|
| 279 |
parse_file = "" |
|---|
| 280 |
# spt is the support macros (e.g., obj/perm sets) - it is an instance of |
|---|
| 281 |
# refpolicy.SupportMacros and should always be present during parsing |
|---|
| 282 |
# though it may not contain any macros. |
|---|
| 283 |
spt = None |
|---|
| 284 |
success = True |
|---|
| 285 |
|
|---|
| 286 |
# utilities |
|---|
| 287 |
def collect(stmts, parent, val=None): |
|---|
| 288 |
if stmts is None: |
|---|
| 289 |
return |
|---|
| 290 |
for s in stmts: |
|---|
| 291 |
if s is None: |
|---|
| 292 |
continue |
|---|
| 293 |
s.parent = parent |
|---|
| 294 |
if val is not None: |
|---|
| 295 |
parent.children.insert(0, (val, s)) |
|---|
| 296 |
else: |
|---|
| 297 |
parent.children.insert(0, s) |
|---|
| 298 |
|
|---|
| 299 |
def expand(ids, s): |
|---|
| 300 |
for id in ids: |
|---|
| 301 |
if spt.has_key(id): |
|---|
| 302 |
s.update(spt.by_name(id)) |
|---|
| 303 |
else: |
|---|
| 304 |
s.add(id) |
|---|
| 305 |
|
|---|
| 306 |
# Top-level non-terminal |
|---|
| 307 |
def p_statements(p): |
|---|
| 308 |
'''statements : statement |
|---|
| 309 |
| statements statement |
|---|
| 310 |
| empty |
|---|
| 311 |
''' |
|---|
| 312 |
if len(p) == 2 and p[1]: |
|---|
| 313 |
m.children.append(p[1]) |
|---|
| 314 |
elif len(p) > 2 and p[2]: |
|---|
| 315 |
m.children.append(p[2]) |
|---|
| 316 |
|
|---|
| 317 |
def p_statement(p): |
|---|
| 318 |
'''statement : interface |
|---|
| 319 |
| template |
|---|
| 320 |
| obj_perm_set |
|---|
| 321 |
| policy |
|---|
| 322 |
| policy_module_stmt |
|---|
| 323 |
| module_stmt |
|---|
| 324 |
''' |
|---|
| 325 |
p[0] = p[1] |
|---|
| 326 |
|
|---|
| 327 |
def p_empty(p): |
|---|
| 328 |
'empty :' |
|---|
| 329 |
pass |
|---|
| 330 |
|
|---|
| 331 |
# |
|---|
| 332 |
# Reference policy language constructs |
|---|
| 333 |
# |
|---|
| 334 |
|
|---|
| 335 |
# This is for the policy module statement (e.g., policy_module(foo,1.2.0)). |
|---|
| 336 |
# We have a separate terminal for either the basic language module statement |
|---|
| 337 |
# and interface calls to make it easier to identifier. |
|---|
| 338 |
def p_policy_module_stmt(p): |
|---|
| 339 |
'policy_module_stmt : POLICY_MODULE OPAREN IDENTIFIER COMMA NUMBER CPAREN' |
|---|
| 340 |
m = refpolicy.ModuleDeclaration() |
|---|
| 341 |
m.name = p[3] |
|---|
| 342 |
m.version = p[5] |
|---|
| 343 |
m.refpolicy = True |
|---|
| 344 |
p[0] = m |
|---|
| 345 |
|
|---|
| 346 |
def p_interface(p): |
|---|
| 347 |
'''interface : INTERFACE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 348 |
''' |
|---|
| 349 |
x = refpolicy.Interface(p[4]) |
|---|
| 350 |
collect(p[8], x) |
|---|
| 351 |
p[0] = x |
|---|
| 352 |
|
|---|
| 353 |
def p_template(p): |
|---|
| 354 |
'''template : TEMPLATE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 355 |
| DEFINE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 356 |
''' |
|---|
| 357 |
x = refpolicy.Template(p[4]) |
|---|
| 358 |
collect(p[8], x) |
|---|
| 359 |
p[0] = x |
|---|
| 360 |
|
|---|
| 361 |
def p_define(p): |
|---|
| 362 |
'''define : DEFINE OPAREN TICK IDENTIFIER SQUOTE CPAREN''' |
|---|
| 363 |
# This is for defining single M4 values (to be used later in ifdef statements). |
|---|
| 364 |
# Example: define(`sulogin_no_pam'). We don't currently do anything with these |
|---|
| 365 |
# but we should in the future when we correctly resolve ifdef statements. |
|---|
| 366 |
p[0] = None |
|---|
| 367 |
|
|---|
| 368 |
def p_interface_stmts(p): |
|---|
| 369 |
'''interface_stmts : policy |
|---|
| 370 |
| interface_stmts policy |
|---|
| 371 |
| empty |
|---|
| 372 |
''' |
|---|
| 373 |
if len(p) == 2 and p[1]: |
|---|
| 374 |
p[0] = p[1] |
|---|
| 375 |
elif len(p) > 2: |
|---|
| 376 |
if not p[1]: |
|---|
| 377 |
if p[2]: |
|---|
| 378 |
p[0] = p[2] |
|---|
| 379 |
elif not p[2]: |
|---|
| 380 |
p[0] = p[1] |
|---|
| 381 |
else: |
|---|
| 382 |
p[0] = p[1] + p[2] |
|---|
| 383 |
|
|---|
| 384 |
def p_optional_policy(p): |
|---|
| 385 |
'''optional_policy : OPT_POLICY OPAREN TICK interface_stmts SQUOTE CPAREN |
|---|
| 386 |
| OPT_POLICY OPAREN TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 387 |
''' |
|---|
| 388 |
o = refpolicy.OptionalPolicy() |
|---|
| 389 |
collect(p[4], o, val=True) |
|---|
| 390 |
if len(p) > 7: |
|---|
| 391 |
collect(p[8], o, val=False) |
|---|
| 392 |
p[0] = [o] |
|---|
| 393 |
|
|---|
| 394 |
def p_tunable_policy(p): |
|---|
| 395 |
'''tunable_policy : TUNABLE_POLICY OPAREN TICK cond_expr SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 396 |
| TUNABLE_POLICY OPAREN TICK cond_expr SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN |
|---|
| 397 |
''' |
|---|
| 398 |
x = refpolicy.TunablePolicy() |
|---|
| 399 |
x.cond_expr = p[4] |
|---|
| 400 |
collect(p[8], x, val=True) |
|---|
| 401 |
if len(p) > 11: |
|---|
| 402 |
collect(p[12], x, val=False) |
|---|
| 403 |
p[0] = [x] |
|---|
| 404 |
|
|---|
| 405 |
def p_ifelse(p): |
|---|
| 406 |
'''ifelse : IFELSE OPAREN TICK IDENTIFIER SQUOTE COMMA COMMA TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi |
|---|
| 407 |
| IFELSE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi |
|---|
| 408 |
''' |
|---|
| 409 |
# x = refpolicy.IfDef(p[4]) |
|---|
| 410 |
# v = True |
|---|
| 411 |
# collect(p[8], x, val=v) |
|---|
| 412 |
# if len(p) > 12: |
|---|
| 413 |
# collect(p[12], x, val=False) |
|---|
| 414 |
# p[0] = [x] |
|---|
| 415 |
pass |
|---|
| 416 |
|
|---|
| 417 |
|
|---|
| 418 |
def p_ifdef(p): |
|---|
| 419 |
'''ifdef : IFDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi |
|---|
| 420 |
| IFNDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi |
|---|
| 421 |
| IFDEF OPAREN TICK IDENTIFIER SQUOTE COMMA TICK interface_stmts SQUOTE COMMA TICK interface_stmts SQUOTE CPAREN optional_semi |
|---|
| 422 |
''' |
|---|
| 423 |
x = refpolicy.IfDef(p[4]) |
|---|
| 424 |
if p[1] == 'ifdef': |
|---|
| 425 |
v = True |
|---|
| 426 |
else: |
|---|
| 427 |
v = False |
|---|
| 428 |
collect(p[8], x, val=v) |
|---|
| 429 |
if len(p) > 12: |
|---|
| 430 |
collect(p[12], x, val=False) |
|---|
| 431 |
p[0] = [x] |
|---|
| 432 |
|
|---|
| 433 |
def p_interface_call(p): |
|---|
| 434 |
'''interface_call : IDENTIFIER OPAREN interface_call_param_list CPAREN |
|---|
| 435 |
| IDENTIFIER OPAREN CPAREN |
|---|
| 436 |
| IDENTIFIER OPAREN interface_call_param_list CPAREN SEMI''' |
|---|
| 437 |
# Allow spurious semi-colons at the end of interface calls |
|---|
| 438 |
i = refpolicy.InterfaceCall(ifname=p[1]) |
|---|
| 439 |
if len(p) > 4: |
|---|
| 440 |
i.args.extend(p[3]) |
|---|
| 441 |
p[0] = i |
|---|
| 442 |
|
|---|
| 443 |
def p_interface_call_param(p): |
|---|
| 444 |
'''interface_call_param : IDENTIFIER |
|---|
| 445 |
| IDENTIFIER MINUS IDENTIFIER |
|---|
| 446 |
| nested_id_set |
|---|
| 447 |
| TRUE |
|---|
| 448 |
| FALSE |
|---|
| 449 |
''' |
|---|
| 450 |
# Intentionally let single identifiers pass through |
|---|
| 451 |
# List means set, non-list identifier |
|---|
| 452 |
if len(p) == 2: |
|---|
| 453 |
p[0] = p[1] |
|---|
| 454 |
else: |
|---|
| 455 |
p[0] = [p[1], "-" + p[3]] |
|---|
| 456 |
|
|---|
| 457 |
def p_interface_call_param_list(p): |
|---|
| 458 |
'''interface_call_param_list : interface_call_param |
|---|
| 459 |
| interface_call_param_list COMMA interface_call_param |
|---|
| 460 |
''' |
|---|
| 461 |
if len(p) == 2: |
|---|
| 462 |
p[0] = [p[1]] |
|---|
| 463 |
else: |
|---|
| 464 |
p[0] = p[1] + [p[3]] |
|---|
| 465 |
|
|---|
| 466 |
|
|---|
| 467 |
def p_obj_perm_set(p): |
|---|
| 468 |
'obj_perm_set : DEFINE OPAREN TICK IDENTIFIER SQUOTE COMMA TICK names SQUOTE CPAREN' |
|---|
| 469 |
s = refpolicy.ObjPermSet(p[4]) |
|---|
| 470 |
s.perms = p[8] |
|---|
| 471 |
p[0] = s |
|---|
| 472 |
|
|---|
| 473 |
# |
|---|
| 474 |
# Basic SELinux policy language |
|---|
| 475 |
# |
|---|
| 476 |
|
|---|
| 477 |
def p_policy(p): |
|---|
| 478 |
'''policy : policy_stmt |
|---|
| 479 |
| optional_policy |
|---|
| 480 |
| tunable_policy |
|---|
| 481 |
| ifdef |
|---|
| 482 |
| ifelse |
|---|
| 483 |
| conditional |
|---|
| 484 |
''' |
|---|
| 485 |
p[0] = p[1] |
|---|
| 486 |
|
|---|
| 487 |
def p_policy_stmt(p): |
|---|
| 488 |
'''policy_stmt : gen_require |
|---|
| 489 |
| avrule_def |
|---|
| 490 |
| typerule_def |
|---|
| 491 |
| typeattribute_def |
|---|
| 492 |
| interface_call |
|---|
| 493 |
| role_def |
|---|
| 494 |
| role_allow |
|---|
| 495 |
| permissive |
|---|
| 496 |
| type_def |
|---|
| 497 |
| typealias_def |
|---|
| 498 |
| attribute_def |
|---|
| 499 |
| range_transition_def |
|---|
| 500 |
| role_transition_def |
|---|
| 501 |
| bool |
|---|
| 502 |
| define |
|---|
| 503 |
| initial_sid |
|---|
| 504 |
| genfscon |
|---|
| 505 |
| fs_use |
|---|
| 506 |
| portcon |
|---|
| 507 |
| nodecon |
|---|
| 508 |
| netifcon |
|---|
| 509 |
| pirqcon |
|---|
| 510 |
| iomemcon |
|---|
| 511 |
| ioportcon |
|---|
| 512 |
| pcidevicecon |
|---|
| 513 |
''' |
|---|
| 514 |
if p[1]: |
|---|
| 515 |
p[0] = [p[1]] |
|---|
| 516 |
|
|---|
| 517 |
def p_module_stmt(p): |
|---|
| 518 |
'module_stmt : MODULE IDENTIFIER NUMBER SEMI' |
|---|
| 519 |
m = refpolicy.ModuleDeclaration() |
|---|
| 520 |
m.name = p[2] |
|---|
| 521 |
m.version = p[3] |
|---|
| 522 |
m.refpolicy = False |
|---|
| 523 |
p[0] = m |
|---|
| 524 |
|
|---|
| 525 |
def p_gen_require(p): |
|---|
| 526 |
'''gen_require : GEN_REQ OPAREN TICK requires SQUOTE CPAREN |
|---|
| 527 |
| REQUIRE OBRACE requires CBRACE''' |
|---|
| 528 |
# We ignore the require statements - they are redundant data from our point-of-view. |
|---|
| 529 |
# Checkmodule will verify them later anyway so we just assume that they match what |
|---|
| 530 |
# is in the rest of the interface. |
|---|
| 531 |
pass |
|---|
| 532 |
|
|---|
| 533 |
def p_requires(p): |
|---|
| 534 |
'''requires : require |
|---|
| 535 |
| requires require |
|---|
| 536 |
| ifdef |
|---|
| 537 |
| requires ifdef |
|---|
| 538 |
''' |
|---|
| 539 |
pass |
|---|
| 540 |
|
|---|
| 541 |
def p_require(p): |
|---|
| 542 |
'''require : TYPE comma_list SEMI |
|---|
| 543 |
| ROLE comma_list SEMI |
|---|
| 544 |
| ATTRIBUTE comma_list SEMI |
|---|
| 545 |
| CLASS comma_list SEMI |
|---|
| 546 |
| BOOL comma_list SEMI |
|---|
| 547 |
''' |
|---|
| 548 |
pass |
|---|
| 549 |
|
|---|
| 550 |
def p_security_context(p): |
|---|
| 551 |
'''security_context : IDENTIFIER COLON IDENTIFIER COLON IDENTIFIER |
|---|
| 552 |
| IDENTIFIER COLON IDENTIFIER COLON IDENTIFIER COLON mls_range_def''' |
|---|
| 553 |
# This will likely need some updates to handle complex levels |
|---|
| 554 |
s = refpolicy.SecurityContext() |
|---|
| 555 |
s.user = p[1] |
|---|
| 556 |
s.role = p[3] |
|---|
| 557 |
s.type = p[5] |
|---|
| 558 |
if len(p) > 6: |
|---|
| 559 |
s.level = p[7] |
|---|
| 560 |
|
|---|
| 561 |
p[0] = s |
|---|
| 562 |
|
|---|
| 563 |
def p_gen_context(p): |
|---|
| 564 |
'''gen_context : GEN_CONTEXT OPAREN security_context COMMA mls_range_def CPAREN |
|---|
| 565 |
''' |
|---|
| 566 |
# We actually store gen_context statements in a SecurityContext |
|---|
| 567 |
# object - it knows how to output either a bare context or a |
|---|
| 568 |
# gen_context statement. |
|---|
| 569 |
s = p[3] |
|---|
| 570 |
s.level = p[5] |
|---|
| 571 |
|
|---|
| 572 |
p[0] = s |
|---|
| 573 |
|
|---|
| 574 |
def p_context(p): |
|---|
| 575 |
'''context : security_context |
|---|
| 576 |
| gen_context |
|---|
| 577 |
''' |
|---|
| 578 |
p[0] = p[1] |
|---|
| 579 |
|
|---|
| 580 |
def p_initial_sid(p): |
|---|
| 581 |
'''initial_sid : SID IDENTIFIER context''' |
|---|
| 582 |
s = refpolicy.InitialSid() |
|---|
| 583 |
s.name = p[2] |
|---|
| 584 |
s.context = p[3] |
|---|
| 585 |
p[0] = s |
|---|
| 586 |
|
|---|
| 587 |
def p_genfscon(p): |
|---|
| 588 |
'''genfscon : GENFSCON IDENTIFIER PATH context''' |
|---|
| 589 |
|
|---|
| 590 |
g = refpolicy.GenfsCon() |
|---|
| 591 |
g.filesystem = p[2] |
|---|
| 592 |
g.path = p[3] |
|---|
| 593 |
g.context = p[4] |
|---|
| 594 |
|
|---|
| 595 |
p[0] = g |
|---|
| 596 |
|
|---|
| 597 |
def p_fs_use(p): |
|---|
| 598 |
'''fs_use : FS_USE_XATTR IDENTIFIER context SEMI |
|---|
| 599 |
| FS_USE_TASK IDENTIFIER context SEMI |
|---|
| 600 |
| FS_USE_TRANS IDENTIFIER context SEMI |
|---|
| 601 |
''' |
|---|
| 602 |
f = refpolicy.FilesystemUse() |
|---|
| 603 |
if p[1] == "fs_use_xattr": |
|---|
| 604 |
f.type = refpolicy.FilesystemUse.XATTR |
|---|
| 605 |
elif p[1] == "fs_use_task": |
|---|
| 606 |
f.type = refpolicy.FilesystemUse.TASK |
|---|
| 607 |
elif p[1] == "fs_use_trans": |
|---|
| 608 |
f.type = refpolicy.FilesystemUse.TRANS |
|---|
| 609 |
|
|---|
| 610 |
f.filesystem = p[2] |
|---|
| 611 |
f.context = p[3] |
|---|
| 612 |
|
|---|
| 613 |
p[0] = f |
|---|
| 614 |
|
|---|
| 615 |
def p_portcon(p): |
|---|
| 616 |
'''portcon : PORTCON IDENTIFIER NUMBER context |
|---|
| 617 |
| PORTCON IDENTIFIER NUMBER MINUS NUMBER context''' |
|---|
| 618 |
c = refpolicy.PortCon() |
|---|
| 619 |
c.port_type = p[2] |
|---|
| 620 |
if len(p) == 5: |
|---|
| 621 |
c.port_number = p[3] |
|---|
| 622 |
c.context = p[4] |
|---|
| 623 |
else: |
|---|
| 624 |
c.port_number = p[3] + "-" + p[4] |
|---|
| 625 |
c.context = p[5] |
|---|
| 626 |
|
|---|
| 627 |
p[0] = c |
|---|
| 628 |
|
|---|
| 629 |
def p_nodecon(p): |
|---|
| 630 |
'''nodecon : NODECON NUMBER NUMBER context |
|---|
| 631 |
| NODECON IPV6_ADDR IPV6_ADDR context |
|---|
| 632 |
''' |
|---|
| 633 |
n = refpolicy.NodeCon() |
|---|
| 634 |
n.start = p[2] |
|---|
| 635 |
n.end = p[3] |
|---|
| 636 |
n.context = p[4] |
|---|
| 637 |
|
|---|
| 638 |
p[0] = n |
|---|
| 639 |
|
|---|
| 640 |
def p_netifcon(p): |
|---|
| 641 |
'netifcon : NETIFCON IDENTIFIER context context' |
|---|
| 642 |
n = refpolicy.NetifCon() |
|---|
| 643 |
n.interface = p[2] |
|---|
| 644 |
n.interface_context = p[3] |
|---|
| 645 |
n.packet_context = p[4] |
|---|
| 646 |
|
|---|
| 647 |
p[0] = n |
|---|
| 648 |
|
|---|
| 649 |
def p_pirqcon(p): |
|---|
| 650 |
'pirqcon : PIRQCON NUMBER context' |
|---|
| 651 |
c = refpolicy.PirqCon() |
|---|
| 652 |
c.pirq_number = p[2] |
|---|
| 653 |
c.context = p[3] |
|---|
| 654 |
|
|---|
| 655 |
p[0] = c |
|---|
| 656 |
|
|---|
| 657 |
def p_iomemcon(p): |
|---|
| 658 |
'''iomemcon : IOMEMCON NUMBER context |
|---|
| 659 |
| IOMEMCON NUMBER MINUS NUMBER context''' |
|---|
| 660 |
c = refpolicy.IomemCon() |
|---|
| 661 |
if len(p) == 4: |
|---|
| 662 |
c.device_mem = p[2] |
|---|
| 663 |
c.context = p[3] |
|---|
| 664 |
else: |
|---|
| 665 |
c.device_mem = p[2] + "-" + p[3] |
|---|
| 666 |
c.context = p[4] |
|---|
| 667 |
|
|---|
| 668 |
p[0] = c |
|---|
| 669 |
|
|---|
| 670 |
def p_ioportcon(p): |
|---|
| 671 |
'''ioportcon : IOPORTCON NUMBER context |
|---|
| 672 |
| IOPORTCON NUMBER MINUS NUMBER context''' |
|---|
| 673 |
c = refpolicy.IoportCon() |
|---|
| 674 |
if len(p) == 4: |
|---|
| 675 |
c.ioport = p[2] |
|---|
| 676 |
c.context = p[3] |
|---|
| 677 |
else: |
|---|
| 678 |
c.ioport = p[2] + "-" + p[3] |
|---|
| 679 |
c.context = p[4] |
|---|
| 680 |
|
|---|
| 681 |
p[0] = c |
|---|
| 682 |
|
|---|
| 683 |
def p_pcidevicecon(p): |
|---|
| 684 |
'pcidevicecon : PCIDEVICECON NUMBER context' |
|---|
| 685 |
c = refpolicy.PciDeviceCon() |
|---|
| 686 |
c.device = p[2] |
|---|
| 687 |
c.context = p[3] |
|---|
| 688 |
|
|---|
| 689 |
p[0] = c |
|---|
| 690 |
|
|---|
| 691 |
def p_mls_range_def(p): |
|---|
| 692 |
'''mls_range_def : mls_level_def MINUS mls_level_def |
|---|
| 693 |
| mls_level_def |
|---|
| 694 |
''' |
|---|
| 695 |
p[0] = p[1] |
|---|
| 696 |
if len(p) > 2: |
|---|
| 697 |
p[0] = p[0] + "-" + p[3] |
|---|
| 698 |
|
|---|
| 699 |
def p_mls_level_def(p): |
|---|
| 700 |
'''mls_level_def : IDENTIFIER COLON comma_list |
|---|
| 701 |
| IDENTIFIER |
|---|
| 702 |
''' |
|---|
| 703 |
p[0] = p[1] |
|---|
| 704 |
if len(p) > 2: |
|---|
| 705 |
p[0] = p[0] + ":" + ",".join(p[3]) |
|---|
| 706 |
|
|---|
| 707 |
def p_type_def(p): |
|---|
| 708 |
'''type_def : TYPE IDENTIFIER COMMA comma_list SEMI |
|---|
| 709 |
| TYPE IDENTIFIER SEMI |
|---|
| 710 |
| TYPE IDENTIFIER ALIAS names SEMI |
|---|
| 711 |
| TYPE IDENTIFIER ALIAS names COMMA comma_list SEMI |
|---|
| 712 |
''' |
|---|
| 713 |
t = refpolicy.Type(p[2]) |
|---|
| 714 |
if len(p) == 6: |
|---|
| 715 |
if p[3] == ',': |
|---|
| 716 |
t.attributes.update(p[4]) |
|---|
| 717 |
else: |
|---|
| 718 |
t.aliases = p[4] |
|---|
| 719 |
elif len(p) > 4: |
|---|
| 720 |
t.aliases = p[4] |
|---|
| 721 |
if len(p) == 8: |
|---|
| 722 |
t.attributes.update(p[6]) |
|---|
| 723 |
p[0] = t |
|---|
| 724 |
|
|---|
| 725 |
def p_attribute_def(p): |
|---|
| 726 |
'attribute_def : ATTRIBUTE IDENTIFIER SEMI' |
|---|
| 727 |
a = refpolicy.Attribute(p[2]) |
|---|
| 728 |
p[0] = a |
|---|
| 729 |
|
|---|
| 730 |
def p_typealias_def(p): |
|---|
| 731 |
'typealias_def : TYPEALIAS IDENTIFIER ALIAS names SEMI' |
|---|
| 732 |
t = refpolicy.TypeAlias() |
|---|
| 733 |
t.type = p[2] |
|---|
| 734 |
t.aliases = p[4] |
|---|
| 735 |
p[0] = t |
|---|
| 736 |
|
|---|
| 737 |
def p_role_def(p): |
|---|
| 738 |
'''role_def : ROLE IDENTIFIER TYPES comma_list SEMI |
|---|
| 739 |
| ROLE IDENTIFIER SEMI''' |
|---|
| 740 |
r = refpolicy.Role() |
|---|
| 741 |
r.role = p[2] |
|---|
| 742 |
if len(p) > 4: |
|---|
| 743 |
r.types.update(p[4]) |
|---|
| 744 |
p[0] = r |
|---|
| 745 |
|
|---|
| 746 |
def p_role_allow(p): |
|---|
| 747 |
'role_allow : ALLOW names names SEMI' |
|---|
| 748 |
r = refpolicy.RoleAllow() |
|---|
| 749 |
r.src_roles = p[2] |
|---|
| 750 |
r.tgt_roles = p[3] |
|---|
| 751 |
p[0] = r |
|---|
| 752 |
|
|---|
| 753 |
def p_permissive(p): |
|---|
| 754 |
'permissive : PERMISSIVE names SEMI' |
|---|
| 755 |
t.skip(1) |
|---|
| 756 |
|
|---|
| 757 |
def p_avrule_def(p): |
|---|
| 758 |
'''avrule_def : ALLOW names names COLON names names SEMI |
|---|
| 759 |
| DONTAUDIT names names COLON names names SEMI |
|---|
| 760 |
| AUDITALLOW names names COLON names names SEMI |
|---|
| 761 |
| NEVERALLOW names names COLON names names SEMI |
|---|
| 762 |
''' |
|---|
| 763 |
a = refpolicy.AVRule() |
|---|
| 764 |
if p[1] == 'dontaudit': |
|---|
| 765 |
a.rule_type = refpolicy.AVRule.DONTAUDIT |
|---|
| 766 |
elif p[1] == 'auditallow': |
|---|
| 767 |
a.rule_type = refpolicy.AVRule.AUDITALLOW |
|---|
| 768 |
elif p[1] == 'neverallow': |
|---|
| 769 |
a.rule_type = refpolicy.AVRule.NEVERALLOW |
|---|
| 770 |
a.src_types = p[2] |
|---|
| 771 |
a.tgt_types = p[3] |
|---|
| 772 |
a.obj_classes = p[5] |
|---|
| 773 |
a.perms = p[6] |
|---|
| 774 |
p[0] = a |
|---|
| 775 |
|
|---|
| 776 |
def p_typerule_def(p): |
|---|
| 777 |
'''typerule_def : TYPE_TRANSITION names names COLON names IDENTIFIER SEMI |
|---|
| 778 |
| TYPE_TRANSITION names names COLON names IDENTIFIER IDENTIFIER SEMI |
|---|
| 779 |
| TYPE_CHANGE names names COLON names IDENTIFIER SEMI |
|---|
| 780 |
| TYPE_MEMBER names names COLON names IDENTIFIER SEMI |
|---|
| 781 |
''' |
|---|
| 782 |
t = refpolicy.TypeRule() |
|---|
| 783 |
if p[1] == 'type_change': |
|---|
| 784 |
t.rule_type = refpolicy.TypeRule.TYPE_CHANGE |
|---|
| 785 |
elif p[1] == 'type_member': |
|---|
| 786 |
t.rule_type = refpolicy.TypeRule.TYPE_MEMBER |
|---|
| 787 |
t.src_types = p[2] |
|---|
| 788 |
t.tgt_types = p[3] |
|---|
| 789 |
t.obj_classes = p[5] |
|---|
| 790 |
t.dest_type = p[6] |
|---|
| 791 |
p[0] = t |
|---|
| 792 |
|
|---|
| 793 |
def p_bool(p): |
|---|
| 794 |
'''bool : BOOL IDENTIFIER TRUE SEMI |
|---|
| 795 |
| BOOL IDENTIFIER FALSE SEMI''' |
|---|
| 796 |
b = refpolicy.Bool() |
|---|
| 797 |
b.name = p[2] |
|---|
| 798 |
if p[3] == "true": |
|---|
| 799 |
b.state = True |
|---|
| 800 |
else: |
|---|
| 801 |
b.state = False |
|---|
| 802 |
p[0] = b |
|---|
| 803 |
|
|---|
| 804 |
def p_conditional(p): |
|---|
| 805 |
''' conditional : IF OPAREN cond_expr CPAREN OBRACE interface_stmts CBRACE |
|---|
| 806 |
| IF OPAREN cond_expr CPAREN OBRACE interface_stmts CBRACE ELSE OBRACE interface_stmts CBRACE |
|---|
| 807 |
''' |
|---|
| 808 |
c = refpolicy.Conditional() |
|---|
| 809 |
c.cond_expr = p[3] |
|---|
| 810 |
collect(p[6], c, val=True) |
|---|
| 811 |
if len(p) > 8: |
|---|
| 812 |
collect(p[10], c, val=False) |
|---|
| 813 |
p[0] = [c] |
|---|
| 814 |
|
|---|
| 815 |
def p_typeattribute_def(p): |
|---|
| 816 |
'''typeattribute_def : TYPEATTRIBUTE IDENTIFIER comma_list SEMI''' |
|---|
| 817 |
t = refpolicy.TypeAttribute() |
|---|
| 818 |
t.type = p[2] |
|---|
| 819 |
t.attributes.update(p[3]) |
|---|
| 820 |
p[0] = t |
|---|
| 821 |
|
|---|
| 822 |
def p_range_transition_def(p): |
|---|
| 823 |
'''range_transition_def : RANGE_TRANSITION names names COLON names mls_range_def SEMI |
|---|
| 824 |
| RANGE_TRANSITION names names names SEMI''' |
|---|
| 825 |
pass |
|---|
| 826 |
|
|---|
| 827 |
def p_role_transition_def(p): |
|---|
| 828 |
'''role_transition_def : ROLE_TRANSITION names names names SEMI''' |
|---|
| 829 |
pass |
|---|
| 830 |
|
|---|
| 831 |
def p_cond_expr(p): |
|---|
| 832 |
'''cond_expr : IDENTIFIER |
|---|
| 833 |
| EXPL cond_expr |
|---|
| 834 |
| cond_expr AMP AMP cond_expr |
|---|
| 835 |
| cond_expr BAR BAR cond_expr |
|---|
| 836 |
| cond_expr EQUAL EQUAL cond_expr |
|---|
| 837 |
| cond_expr EXPL EQUAL cond_expr |
|---|
| 838 |
''' |
|---|
| 839 |
l = len(p) |
|---|
| 840 |
if l == 2: |
|---|
| 841 |
p[0] = [p[1]] |
|---|
| 842 |
elif l == 3: |
|---|
| 843 |
p[0] = [p[1]] + p[2] |
|---|
| 844 |
else: |
|---|
| 845 |
p[0] = p[1] + [p[2] + p[3]] + p[4] |
|---|
| 846 |
|
|---|
| 847 |
|
|---|
| 848 |
# |
|---|
| 849 |
# Basic terminals |
|---|
| 850 |
# |
|---|
| 851 |
|
|---|
| 852 |
# Identifiers and lists of identifiers. These must |
|---|
| 853 |
# be handled somewhat gracefully. Names returns an IdSet and care must |
|---|
| 854 |
# be taken that this is _assigned_ to an object to correctly update |
|---|
| 855 |
# all of the flags (as opposed to using update). The other terminals |
|---|
| 856 |
# return list - this is to preserve ordering if it is important for |
|---|
| 857 |
# parsing (for example, interface_call must retain the ordering). Other |
|---|
| 858 |
# times the list should be used to update an IdSet. |
|---|
| 859 |
|
|---|
| 860 |
def p_names(p): |
|---|
| 861 |
'''names : identifier |
|---|
| 862 |
| nested_id_set |
|---|
| 863 |
| asterisk |
|---|
| 864 |
| TILDE identifier |
|---|
| 865 |
| TILDE nested_id_set |
|---|
| 866 |
| IDENTIFIER MINUS IDENTIFIER |
|---|
| 867 |
''' |
|---|
| 868 |
s = refpolicy.IdSet() |
|---|
| 869 |
if len(p) < 3: |
|---|
| 870 |
expand(p[1], s) |
|---|
| 871 |
elif len(p) == 3: |
|---|
| 872 |
expand(p[2], s) |
|---|
| 873 |
s.compliment = True |
|---|
| 874 |
else: |
|---|
| 875 |
expand([p[1]]) |
|---|
| 876 |
s.add("-" + p[3]) |
|---|
| 877 |
p[0] = s |
|---|
| 878 |
|
|---|
| 879 |
def p_identifier(p): |
|---|
| 880 |
'identifier : IDENTIFIER' |
|---|
| 881 |
p[0] = [p[1]] |
|---|
| 882 |
|
|---|
| 883 |
def p_asterisk(p): |
|---|
| 884 |
'asterisk : ASTERISK' |
|---|
| 885 |
p[0] = [p[1]] |
|---|
| 886 |
|
|---|
| 887 |
def p_nested_id_set(p): |
|---|
| 888 |
'''nested_id_set : OBRACE nested_id_list CBRACE |
|---|
| 889 |
''' |
|---|
| 890 |
p[0] = p[2] |
|---|
| 891 |
|
|---|
| 892 |
def p_nested_id_list(p): |
|---|
| 893 |
'''nested_id_list : nested_id_element |
|---|
| 894 |
| nested_id_list nested_id_element |
|---|
| 895 |
''' |
|---|
| 896 |
if len(p) == 2: |
|---|
| 897 |
p[0] = p[1] |
|---|
| 898 |
else: |
|---|
| 899 |
p[0] = p[1] + p[2] |
|---|
| 900 |
|
|---|
| 901 |
def p_nested_id_element(p): |
|---|
| 902 |
'''nested_id_element : identifier |
|---|
| 903 |
| MINUS IDENTIFIER |
|---|
| 904 |
| nested_id_set |
|---|
| 905 |
''' |
|---|
| 906 |
if len(p) == 2: |
|---|
| 907 |
p[0] = p[1] |
|---|
| 908 |
else: |
|---|
| 909 |
# For now just leave the '-' |
|---|
| 910 |
str = "-" + p[2] |
|---|
| 911 |
p[0] = [str] |
|---|
| 912 |
|
|---|
| 913 |
def p_comma_list(p): |
|---|
| 914 |
'''comma_list : nested_id_list |
|---|
| 915 |
| comma_list COMMA nested_id_list |
|---|
| 916 |
''' |
|---|
| 917 |
if len(p) > 2: |
|---|
| 918 |
p[1] = p[1] + p[3] |
|---|
| 919 |
p[0] = p[1] |
|---|
| 920 |
|
|---|
| 921 |
def p_optional_semi(p): |
|---|
| 922 |
'''optional_semi : SEMI |
|---|
| 923 |
| empty''' |
|---|
| 924 |
pass |
|---|
| 925 |
|
|---|
| 926 |
|
|---|
| 927 |
# |
|---|
| 928 |
# Interface to the parser |
|---|
| 929 |
# |
|---|
| 930 |
|
|---|
| 931 |
def p_error(tok): |
|---|
| 932 |
global error, parse_file, success, parser |
|---|
| 933 |
error = "%s: Syntax error on line %d %s [type=%s]" % (parse_file, tok.lineno, tok.value, tok.type) |
|---|
| 934 |
print error |
|---|
| 935 |
success = False |
|---|
| 936 |
|
|---|
| 937 |
def prep_spt(spt): |
|---|
| 938 |
if not spt: |
|---|
| 939 |
return { } |
|---|
| 940 |
map = {} |
|---|
| 941 |
for x in spt: |
|---|
| 942 |
map[x.name] = x |
|---|
| 943 |
|
|---|
| 944 |
parser = None |
|---|
| 945 |
lexer = None |
|---|
| 946 |
def create_globals(module, support, debug): |
|---|
| 947 |
global parser, lexer, m, spt |
|---|
| 948 |
|
|---|
| 949 |
if not parser: |
|---|
| 950 |
lexer = lex.lex() |
|---|
| 951 |
parser = yacc.yacc(method="LALR", debug=debug, write_tables=0) |
|---|
| 952 |
|
|---|
| 953 |
if module is not None: |
|---|
| 954 |
m = module |
|---|
| 955 |
else: |
|---|
| 956 |
m = refpolicy.Module() |
|---|
| 957 |
|
|---|
| 958 |
if not support: |
|---|
| 959 |
spt = refpolicy.SupportMacros() |
|---|
| 960 |
else: |
|---|
| 961 |
spt = support |
|---|
| 962 |
|
|---|
| 963 |
def parse(text, module=None, support=None, debug=False): |
|---|
| 964 |
create_globals(module, support, debug) |
|---|
| 965 |
global error, parser, lexer, success |
|---|
| 966 |
|
|---|
| 967 |
success = True |
|---|
| 968 |
|
|---|
| 969 |
try: |
|---|
| 970 |
parser.parse(text, debug=debug, lexer=lexer) |
|---|
| 971 |
except Exception, e: |
|---|
| 972 |
parser = None |
|---|
| 973 |
lexer = None |
|---|
| 974 |
error = "internal parser error: %s" % str(e) + "\n" + traceback.format_exc() |
|---|
| 975 |
|
|---|
| 976 |
if not success: |
|---|
| 977 |
# force the parser and lexer to be rebuilt - we have some problems otherwise |
|---|
| 978 |
parser = None |
|---|
| 979 |
msg = 'could not parse text: "%s"' % error |
|---|
| 980 |
raise ValueError(msg) |
|---|
| 981 |
return m |
|---|
| 982 |
|
|---|
| 983 |
def list_headers(root): |
|---|
| 984 |
modules = [] |
|---|
| 985 |
support_macros = None |
|---|
| 986 |
|
|---|
| 987 |
for dirpath, dirnames, filenames in os.walk(root): |
|---|
| 988 |
for name in filenames: |
|---|
| 989 |
modname = os.path.splitext(name) |
|---|
| 990 |
filename = os.path.join(dirpath, name) |
|---|
| 991 |
|
|---|
| 992 |
if modname[1] == '.spt': |
|---|
| 993 |
if name == "obj_perm_sets.spt": |
|---|
| 994 |
support_macros = filename |
|---|
| 995 |
elif len(re.findall("patterns", modname[0])): |
|---|
| 996 |
modules.append((modname[0], filename)) |
|---|
| 997 |
elif modname[1] == '.if': |
|---|
| 998 |
modules.append((modname[0], filename)) |
|---|
| 999 |
|
|---|
| 1000 |
return (modules, support_macros) |
|---|
| 1001 |
|
|---|
| 1002 |
|
|---|
| 1003 |
def parse_headers(root, output=None, expand=True, debug=False): |
|---|
| 1004 |
import util |
|---|
| 1005 |
|
|---|
| 1006 |
headers = refpolicy.Headers() |
|---|
| 1007 |
|
|---|
| 1008 |
modules = [] |
|---|
| 1009 |
support_macros = None |
|---|
| 1010 |
|
|---|
| 1011 |
if os.path.isfile(root): |
|---|
| 1012 |
name = os.path.split(root)[1] |
|---|
| 1013 |
if name == '': |
|---|
| 1014 |
raise ValueError("Invalid file name %s" % root) |
|---|
| 1015 |
modname = os.path.splitext(name) |
|---|
| 1016 |
modules.append((modname[0], root)) |
|---|
| 1017 |
all_modules, support_macros = list_headers(defaults.headers()) |
|---|
| 1018 |
else: |
|---|
| 1019 |
modules, support_macros = list_headers(root) |
|---|
| 1020 |
|
|---|
| 1021 |
if expand and not support_macros: |
|---|
| 1022 |
raise ValueError("could not find support macros (obj_perm_sets.spt)") |
|---|
| 1023 |
|
|---|
| 1024 |
def o(msg): |
|---|
| 1025 |
if output: |
|---|
| 1026 |
output.write(msg) |
|---|
| 1027 |
|
|---|
| 1028 |
def parse_file(f, module, spt=None): |
|---|
| 1029 |
global parse_file |
|---|
| 1030 |
if debug: |
|---|
| 1031 |
o("parsing file %s\n" % f) |
|---|
| 1032 |
try: |
|---|
| 1033 |
fd = open(f) |
|---|
| 1034 |
txt = fd.read() |
|---|
| 1035 |
fd.close() |
|---|
| 1036 |
parse_file = f |
|---|
| 1037 |
parse(txt, module, spt, debug) |
|---|
| 1038 |
except IOError, e: |
|---|
| 1039 |
return |
|---|
| 1040 |
except ValueError, e: |
|---|
| 1041 |
raise ValueError("error parsing file %s: %s" % (f, str(e))) |
|---|
| 1042 |
|
|---|
| 1043 |
spt = None |
|---|
| 1044 |
if support_macros: |
|---|
| 1045 |
o("Parsing support macros (%s): " % support_macros) |
|---|
| 1046 |
spt = refpolicy.SupportMacros() |
|---|
| 1047 |
parse_file(support_macros, spt) |
|---|
| 1048 |
|
|---|
| 1049 |
headers.children.append(spt) |
|---|
| 1050 |
|
|---|
| 1051 |
# FIXME: Total hack - add in can_exec rather than parse the insanity |
|---|
| 1052 |
# of misc_macros. We are just going to pretend that this is an interface |
|---|
| 1053 |
# to make the expansion work correctly. |
|---|
| 1054 |
can_exec = refpolicy.Interface("can_exec") |
|---|
| 1055 |
av = access.AccessVector(["$1","$2","file","execute_no_trans","open", "read", |
|---|
| 1056 |
"getattr","lock","execute","ioctl"]) |
|---|
| 1057 |
|
|---|
| 1058 |
can_exec.children.append(refpolicy.AVRule(av)) |
|---|
| 1059 |
headers.children.append(can_exec) |
|---|
| 1060 |
|
|---|
| 1061 |
o("done.\n") |
|---|
| 1062 |
|
|---|
| 1063 |
if output and not debug: |
|---|
| 1064 |
status = util.ConsoleProgressBar(sys.stdout, steps=len(modules)) |
|---|
| 1065 |
status.start("Parsing interface files") |
|---|
| 1066 |
|
|---|
| 1067 |
failures = [] |
|---|
| 1068 |
for x in modules: |
|---|
| 1069 |
m = refpolicy.Module() |
|---|
| 1070 |
m.name = x[0] |
|---|
| 1071 |
try: |
|---|
| 1072 |
if expand: |
|---|
| 1073 |
parse_file(x[1], m, spt) |
|---|
| 1074 |
else: |
|---|
| 1075 |
parse_file(x[1], m) |
|---|
| 1076 |
except ValueError, e: |
|---|
| 1077 |
o(str(e) + "\n") |
|---|
| 1078 |
failures.append(x[1]) |
|---|
| 1079 |
continue |
|---|
| 1080 |
|
|---|
| 1081 |
headers.children.append(m) |
|---|
| 1082 |
if output and not debug: |
|---|
| 1083 |
status.step() |
|---|
| 1084 |
|
|---|
| 1085 |
if len(failures): |
|---|
| 1086 |
o("failed to parse some headers: %s" % ", ".join(failures)) |
|---|
| 1087 |
|
|---|
| 1088 |
return headers |
|---|