forked from SELinuxProject/setools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
seinfoflow
executable file
·156 lines (129 loc) · 5.76 KB
/
seinfoflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
# Copyright 2014-2015, Tresys Technology, LLC
#
# SPDX-License-Identifier: GPL-2.0-only
#
import setools
import argparse
import sys
import logging
import signal
import warnings
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("--full", help="Print full rule lists for information flows.",
action="store_true")
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",
help="Path to alternative 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("-r", "--reverse", action="store_false",
help="Display information flows into the source type. "
"No effect if a target type is specified.")
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')
if not sys.warnoptions:
warnings.simplefilter("default")
elif args.verbose:
logging.basicConfig(level=logging.INFO, format='%(message)s')
if not sys.warnoptions:
warnings.simplefilter("default")
else:
logging.basicConfig(level=logging.WARNING, format='%(message)s')
if not sys.warnoptions:
warnings.simplefilter("ignore")
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))
if args.full:
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, out=args.reverse), start=1):
print("Flow {0}: {1} -> {2}".format(flownum, flow.source, flow.target))
if args.full:
for rule in sorted(flow.rules):
print(" ", rule)
print()
if args.limit_flows and flownum >= args.limit_flows:
break
print("\n{} information flow(s) found.".format(flownum))
if args.stats:
print("\nGraph statistics:")
print(g.get_stats())
except Exception as err:
if args.debug:
raise
else:
print(err)
sys.exit(1)