Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
sepolicy
Manage
Activity
Members
Plan
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Analyze
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
CodeLinaro
public-release-test
platform
system
sepolicy
Commits
ddd47b0b
Commit
ddd47b0b
authored
10 years ago
by
Daniel Cashman
Committed by
Gerrit Code Review
10 years ago
Browse files
Options
Downloads
Plain Diff
Merge "Add neverallow checking to sepolicy-analyze."
parents
8c6dba90
59906bf8
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
tools/README
+34
-0
34 additions, 0 deletions
tools/README
tools/sepolicy-analyze.c
+462
-5
462 additions, 5 deletions
tools/sepolicy-analyze.c
with
496 additions
and
5 deletions
tools/README
+
34
−
0
View file @
ddd47b0b
...
@@ -94,3 +94,37 @@ sepolicy-analyze
...
@@ -94,3 +94,37 @@ sepolicy-analyze
-foo -bar is expanded to individual allow rules by the policy
-foo -bar is expanded to individual allow rules by the policy
compiler). Domains with unconfineddomain will typically have such
compiler). Domains with unconfineddomain will typically have such
duplicate rules as a natural side effect and can be ignored.
duplicate rules as a natural side effect and can be ignored.
PERMISSIVE DOMAINS
sepolicy-analyze -p -P out/target/product/<board>/root/sepolicy
Displays domains in the policy that are permissive, i.e. avc
denials are logged but not enforced for these domains. While
permissive domains can be helpful during development, they
should not be present in a final -user build.
NEVERALLOW CHECKING
sepolicy-analyze [-w] [-z] -n neverallows.conf -P out/target/product/<board>/root/sepolicy
Check whether the sepolicy file violates any of the neverallow rules
from neverallows.conf. neverallows.conf is a file containing neverallow
statements in the same format as the SELinux policy.conf file, i.e. after
m4 macro expansion of the rules from a .te file. You can use an entire
policy.conf file as the neverallows.conf file and sepolicy-analyze will
ignore everything except for the neverallows within it. If there are
no violations, sepolicy-analyze will exit successfully with no output.
Otherwise, sepolicy-analyze will report all violations and exit
with a non-zero exit status.
The -w or --warn option may be used to warn on any types, attributes,
classes, or permissions from a neverallow rule that could not be resolved
within the sepolicy file. This can be normal due to differences between
the policy from which the neverallow rules were taken and the policy
being checked. Such values are ignored for the purposes of neverallow
checking.
The -z (-d was already taken!) or --debug option may be used to cause
sepolicy-analyze to emit the neverallow rules as it parses them from
the neverallows.conf file. This is principally a debugging facility
for the parser but could also be used to extract neverallow rules from
a full policy.conf file and output them in a more easily parsed format.
This diff is collapsed.
Click to expand it.
tools/sepolicy-analyze.c
+
462
−
5
View file @
ddd47b0b
...
@@ -13,9 +13,12 @@
...
@@ -13,9 +13,12 @@
#include
<sepol/policydb/util.h>
#include
<sepol/policydb/util.h>
#include
<stdbool.h>
#include
<stdbool.h>
static
int
debug
;
static
int
warn
;
void
usage
(
char
*
arg0
)
void
usage
(
char
*
arg0
)
{
{
fprintf
(
stderr
,
"%s [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] -P <policy file>
\n
"
,
arg0
);
fprintf
(
stderr
,
"%s
[-w|--warn] [-z|--debug]
[-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive]
[-n|--neverallow <neverallow file>]
-P <policy file>
\n
"
,
arg0
);
exit
(
1
);
exit
(
1
);
}
}
...
@@ -425,24 +428,466 @@ static int list_permissive(policydb_t * policydb)
...
@@ -425,24 +428,466 @@ static int list_permissive(policydb_t * policydb)
return
0
;
return
0
;
}
}
static
int
read_typeset
(
policydb_t
*
policydb
,
char
**
ptr
,
char
*
end
,
type_set_t
*
typeset
,
uint32_t
*
flags
)
{
const
char
*
keyword
=
"self"
;
size_t
keyword_size
=
strlen
(
keyword
),
len
;
char
*
p
=
*
ptr
;
unsigned
openparens
=
0
;
char
*
start
,
*
id
;
type_datum_t
*
type
;
struct
ebitmap_node
*
n
;
unsigned
int
bit
;
bool
negate
=
false
;
int
rc
;
do
{
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
)
goto
err
;
if
(
*
p
==
'~'
)
{
if
(
debug
)
printf
(
" ~"
);
typeset
->
flags
=
TYPE_COMP
;
p
++
;
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
)
goto
err
;
}
if
(
*
p
==
'{'
)
{
if
(
debug
&&
!
openparens
)
printf
(
" {"
);
openparens
++
;
p
++
;
continue
;
}
if
(
*
p
==
'}'
)
{
if
(
debug
&&
openparens
==
1
)
printf
(
" }"
);
if
(
openparens
==
0
)
goto
err
;
openparens
--
;
p
++
;
continue
;
}
if
(
*
p
==
'*'
)
{
if
(
debug
)
printf
(
" *"
);
typeset
->
flags
=
TYPE_STAR
;
p
++
;
continue
;
}
if
(
*
p
==
'-'
)
{
if
(
debug
)
printf
(
" -"
);
negate
=
true
;
p
++
;
continue
;
}
if
(
*
p
==
'#'
)
{
while
(
p
<
end
&&
*
p
!=
'\n'
)
p
++
;
continue
;
}
start
=
p
;
while
(
p
<
end
&&
!
isspace
(
*
p
)
&&
*
p
!=
':'
&&
*
p
!=
';'
&&
*
p
!=
'{'
&&
*
p
!=
'}'
&&
*
p
!=
'#'
)
p
++
;
if
(
p
==
start
)
goto
err
;
len
=
p
-
start
;
if
(
len
==
keyword_size
&&
!
strncmp
(
start
,
keyword
,
keyword_size
))
{
if
(
debug
)
printf
(
" self"
);
*
flags
|=
RULE_SELF
;
continue
;
}
id
=
calloc
(
1
,
len
+
1
);
if
(
!
id
)
goto
err
;
memcpy
(
id
,
start
,
len
);
if
(
debug
)
printf
(
" %s"
,
id
);
type
=
hashtab_search
(
policydb
->
p_types
.
table
,
id
);
if
(
!
type
)
{
if
(
warn
)
fprintf
(
stderr
,
"Warning! Type or attribute %s used in neverallow undefined in policy being checked.
\n
"
,
id
);
negate
=
false
;
continue
;
}
free
(
id
);
if
(
type
->
flavor
==
TYPE_ATTRIB
)
{
if
(
negate
)
rc
=
ebitmap_union
(
&
typeset
->
negset
,
&
policydb
->
attr_type_map
[
type
->
s
.
value
-
1
]);
else
rc
=
ebitmap_union
(
&
typeset
->
types
,
&
policydb
->
attr_type_map
[
type
->
s
.
value
-
1
]);
}
else
if
(
negate
)
{
rc
=
ebitmap_set_bit
(
&
typeset
->
negset
,
type
->
s
.
value
-
1
,
1
);
}
else
{
rc
=
ebitmap_set_bit
(
&
typeset
->
types
,
type
->
s
.
value
-
1
,
1
);
}
negate
=
false
;
if
(
rc
)
goto
err
;
}
while
(
p
<
end
&&
openparens
);
if
(
p
==
end
)
goto
err
;
if
(
typeset
->
flags
&
TYPE_STAR
)
{
for
(
bit
=
0
;
bit
<
policydb
->
p_types
.
nprim
;
bit
++
)
{
if
(
ebitmap_get_bit
(
&
typeset
->
negset
,
bit
))
continue
;
if
(
policydb
->
type_val_to_struct
[
bit
]
&&
policydb
->
type_val_to_struct
[
bit
]
->
flavor
==
TYPE_ATTRIB
)
continue
;
if
(
ebitmap_set_bit
(
&
typeset
->
types
,
bit
,
1
))
goto
err
;
}
}
ebitmap_for_each_bit
(
&
typeset
->
negset
,
n
,
bit
)
{
if
(
!
ebitmap_node_get_bit
(
n
,
bit
))
continue
;
if
(
ebitmap_set_bit
(
&
typeset
->
types
,
bit
,
0
))
goto
err
;
}
if
(
typeset
->
flags
&
TYPE_COMP
)
{
for
(
bit
=
0
;
bit
<
policydb
->
p_types
.
nprim
;
bit
++
)
{
if
(
policydb
->
type_val_to_struct
[
bit
]
&&
policydb
->
type_val_to_struct
[
bit
]
->
flavor
==
TYPE_ATTRIB
)
continue
;
if
(
ebitmap_get_bit
(
&
typeset
->
types
,
bit
))
ebitmap_set_bit
(
&
typeset
->
types
,
bit
,
0
);
else
{
if
(
ebitmap_set_bit
(
&
typeset
->
types
,
bit
,
1
))
goto
err
;
}
}
}
if
(
warn
&&
ebitmap_length
(
&
typeset
->
types
)
==
0
&&
!
(
*
flags
))
fprintf
(
stderr
,
"Warning! Empty type set
\n
"
);
*
ptr
=
p
;
return
0
;
err:
return
-
1
;
}
static
int
read_classperms
(
policydb_t
*
policydb
,
char
**
ptr
,
char
*
end
,
class_perm_node_t
**
perms
)
{
char
*
p
=
*
ptr
;
unsigned
openparens
=
0
;
char
*
id
,
*
start
;
class_datum_t
*
cls
=
NULL
;
perm_datum_t
*
perm
=
NULL
;
class_perm_node_t
*
classperms
=
NULL
,
*
node
=
NULL
;
bool
complement
=
false
;
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
||
*
p
!=
':'
)
goto
err
;
p
++
;
if
(
debug
)
printf
(
" :"
);
do
{
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
)
goto
err
;
if
(
*
p
==
'{'
)
{
if
(
debug
&&
!
openparens
)
printf
(
" {"
);
openparens
++
;
p
++
;
continue
;
}
if
(
*
p
==
'}'
)
{
if
(
debug
&&
openparens
==
1
)
printf
(
" }"
);
if
(
openparens
==
0
)
goto
err
;
openparens
--
;
p
++
;
continue
;
}
if
(
*
p
==
'#'
)
{
while
(
p
<
end
&&
*
p
!=
'\n'
)
p
++
;
continue
;
}
start
=
p
;
while
(
p
<
end
&&
!
isspace
(
*
p
)
&&
*
p
!=
'{'
&&
*
p
!=
'}'
&&
*
p
!=
';'
&&
*
p
!=
'#'
)
p
++
;
if
(
p
==
start
)
goto
err
;
id
=
calloc
(
1
,
p
-
start
+
1
);
if
(
!
id
)
goto
err
;
memcpy
(
id
,
start
,
p
-
start
);
if
(
debug
)
printf
(
" %s"
,
id
);
cls
=
hashtab_search
(
policydb
->
p_classes
.
table
,
id
);
if
(
!
cls
)
{
if
(
warn
)
fprintf
(
stderr
,
"Warning! Class %s used in neverallow undefined in policy being checked.
\n
"
,
id
);
continue
;
}
node
=
calloc
(
1
,
sizeof
*
node
);
if
(
!
node
)
goto
err
;
node
->
class
=
cls
->
s
.
value
;
node
->
next
=
classperms
;
classperms
=
node
;
free
(
id
);
}
while
(
p
<
end
&&
openparens
);
if
(
p
==
end
)
goto
err
;
if
(
warn
&&
!
classperms
)
fprintf
(
stderr
,
"Warning! Empty class set
\n
"
);
do
{
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
)
goto
err
;
if
(
*
p
==
'~'
)
{
if
(
debug
)
printf
(
" ~"
);
complement
=
true
;
p
++
;
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
p
==
end
)
goto
err
;
}
if
(
*
p
==
'{'
)
{
if
(
debug
&&
!
openparens
)
printf
(
" {"
);
openparens
++
;
p
++
;
continue
;
}
if
(
*
p
==
'}'
)
{
if
(
debug
&&
openparens
==
1
)
printf
(
" }"
);
if
(
openparens
==
0
)
goto
err
;
openparens
--
;
p
++
;
continue
;
}
if
(
*
p
==
'#'
)
{
while
(
p
<
end
&&
*
p
!=
'\n'
)
p
++
;
continue
;
}
start
=
p
;
while
(
p
<
end
&&
!
isspace
(
*
p
)
&&
*
p
!=
'{'
&&
*
p
!=
'}'
&&
*
p
!=
';'
&&
*
p
!=
'#'
)
p
++
;
if
(
p
==
start
)
goto
err
;
id
=
calloc
(
1
,
p
-
start
+
1
);
if
(
!
id
)
goto
err
;
memcpy
(
id
,
start
,
p
-
start
);
if
(
debug
)
printf
(
" %s"
,
id
);
if
(
!
strcmp
(
id
,
"*"
))
{
for
(
node
=
classperms
;
node
;
node
=
node
->
next
)
node
->
data
=
~
0
;
continue
;
}
for
(
node
=
classperms
;
node
;
node
=
node
->
next
)
{
cls
=
policydb
->
class_val_to_struct
[
node
->
class
-
1
];
perm
=
hashtab_search
(
cls
->
permissions
.
table
,
id
);
if
(
cls
->
comdatum
&&
!
perm
)
perm
=
hashtab_search
(
cls
->
comdatum
->
permissions
.
table
,
id
);
if
(
!
perm
)
{
if
(
warn
)
fprintf
(
stderr
,
"Warning! Permission %s used in neverallow undefined in class %s in policy being checked.
\n
"
,
id
,
policydb
->
p_class_val_to_name
[
node
->
class
-
1
]);
continue
;
}
node
->
data
|=
1U
<<
(
perm
->
s
.
value
-
1
);
}
free
(
id
);
}
while
(
p
<
end
&&
openparens
);
if
(
p
==
end
)
goto
err
;
if
(
complement
)
{
for
(
node
=
classperms
;
node
;
node
=
node
->
next
)
node
->
data
=
~
node
->
data
;
}
if
(
warn
)
{
for
(
node
=
classperms
;
node
;
node
=
node
->
next
)
if
(
!
node
->
data
)
fprintf
(
stderr
,
"Warning! Empty permission set
\n
"
);
}
*
perms
=
classperms
;
*
ptr
=
p
;
return
0
;
err:
return
-
1
;
}
static
int
check_neverallows
(
policydb_t
*
policydb
,
const
char
*
filename
)
{
const
char
*
keyword
=
"neverallow"
;
size_t
keyword_size
=
strlen
(
keyword
),
len
;
struct
avrule
*
neverallows
=
NULL
,
*
avrule
;
int
fd
;
struct
stat
sb
;
char
*
text
,
*
end
,
*
start
;
char
*
p
;
fd
=
open
(
filename
,
O_RDONLY
);
if
(
fd
<
0
)
{
fprintf
(
stderr
,
"Could not open %s: %s
\n
"
,
filename
,
strerror
(
errno
));
return
-
1
;
}
if
(
fstat
(
fd
,
&
sb
)
<
0
)
{
fprintf
(
stderr
,
"Can't stat '%s': %s
\n
"
,
filename
,
strerror
(
errno
));
close
(
fd
);
return
-
1
;
}
text
=
mmap
(
NULL
,
sb
.
st_size
,
PROT_READ
,
MAP_PRIVATE
,
fd
,
0
);
end
=
text
+
sb
.
st_size
;
if
(
text
==
MAP_FAILED
)
{
fprintf
(
stderr
,
"Can't mmap '%s': %s
\n
"
,
filename
,
strerror
(
errno
));
close
(
fd
);
return
-
1
;
}
close
(
fd
);
p
=
text
;
while
(
p
<
end
)
{
while
(
p
<
end
&&
isspace
(
*
p
))
p
++
;
if
(
*
p
==
'#'
)
{
while
(
p
<
end
&&
*
p
!=
'\n'
)
p
++
;
continue
;
}
start
=
p
;
while
(
p
<
end
&&
!
isspace
(
*
p
))
p
++
;
len
=
p
-
start
;
if
(
len
!=
keyword_size
||
strncmp
(
start
,
keyword
,
keyword_size
))
continue
;
if
(
debug
)
printf
(
"neverallow"
);
avrule
=
calloc
(
1
,
sizeof
*
avrule
);
if
(
!
avrule
)
goto
err
;
avrule
->
specified
=
AVRULE_NEVERALLOW
;
if
(
read_typeset
(
policydb
,
&
p
,
end
,
&
avrule
->
stypes
,
&
avrule
->
flags
))
goto
err
;
if
(
read_typeset
(
policydb
,
&
p
,
end
,
&
avrule
->
ttypes
,
&
avrule
->
flags
))
goto
err
;
if
(
read_classperms
(
policydb
,
&
p
,
end
,
&
avrule
->
perms
))
goto
err
;
while
(
p
<
end
&&
*
p
!=
';'
)
p
++
;
if
(
p
==
end
||
*
p
!=
';'
)
goto
err
;
if
(
debug
)
printf
(
";
\n
"
);
avrule
->
next
=
neverallows
;
neverallows
=
avrule
;
}
return
check_assertions
(
NULL
,
policydb
,
neverallows
);
err:
if
(
errno
==
ENOMEM
)
{
fprintf
(
stderr
,
"Out of memory while parsing %s
\n
"
,
filename
);
}
else
fprintf
(
stderr
,
"Error while parsing %s
\n
"
,
filename
);
return
-
1
;
}
int
main
(
int
argc
,
char
**
argv
)
int
main
(
int
argc
,
char
**
argv
)
{
{
char
*
policy
=
NULL
;
char
*
policy
=
NULL
,
*
neverallows
=
NULL
;
struct
policy_file
pf
;
struct
policy_file
pf
;
policydb_t
policydb
;
policydb_t
policydb
;
char
ch
;
char
ch
;
char
equiv
=
0
,
diff
=
0
,
dups
=
0
,
permissive
=
0
;
char
equiv
=
0
,
diff
=
0
,
dups
=
0
,
permissive
=
0
;
int
rc
=
0
;
struct
option
long_options
[]
=
{
struct
option
long_options
[]
=
{
{
"equiv"
,
no_argument
,
NULL
,
'e'
},
{
"equiv"
,
no_argument
,
NULL
,
'e'
},
{
"debug"
,
no_argument
,
NULL
,
'z'
},
{
"diff"
,
no_argument
,
NULL
,
'd'
},
{
"diff"
,
no_argument
,
NULL
,
'd'
},
{
"dups"
,
no_argument
,
NULL
,
'D'
},
{
"dups"
,
no_argument
,
NULL
,
'D'
},
{
"neverallow"
,
required_argument
,
NULL
,
'n'
},
{
"permissive"
,
no_argument
,
NULL
,
'p'
},
{
"permissive"
,
no_argument
,
NULL
,
'p'
},
{
"policy"
,
required_argument
,
NULL
,
'P'
},
{
"policy"
,
required_argument
,
NULL
,
'P'
},
{
"warn"
,
no_argument
,
NULL
,
'w'
},
{
NULL
,
0
,
NULL
,
0
}
{
NULL
,
0
,
NULL
,
0
}
};
};
while
((
ch
=
getopt_long
(
argc
,
argv
,
"edDp
P:
"
,
long_options
,
NULL
))
!=
-
1
)
{
while
((
ch
=
getopt_long
(
argc
,
argv
,
"edDp
n:P:wz
"
,
long_options
,
NULL
))
!=
-
1
)
{
switch
(
ch
)
{
switch
(
ch
)
{
case
'e'
:
case
'e'
:
equiv
=
1
;
equiv
=
1
;
...
@@ -453,18 +898,27 @@ int main(int argc, char **argv)
...
@@ -453,18 +898,27 @@ int main(int argc, char **argv)
case
'D'
:
case
'D'
:
dups
=
1
;
dups
=
1
;
break
;
break
;
case
'n'
:
neverallows
=
optarg
;
break
;
case
'p'
:
case
'p'
:
permissive
=
1
;
permissive
=
1
;
break
;
break
;
case
'P'
:
case
'P'
:
policy
=
optarg
;
policy
=
optarg
;
break
;
break
;
case
'w'
:
warn
=
1
;
break
;
case
'z'
:
debug
=
1
;
break
;
default:
default:
usage
(
argv
[
0
]);
usage
(
argv
[
0
]);
}
}
}
}
if
(
!
policy
||
(
!
equiv
&&
!
diff
&&
!
dups
&&
!
permissive
))
if
(
!
policy
||
(
!
equiv
&&
!
diff
&&
!
dups
&&
!
permissive
&&
!
neverallows
))
usage
(
argv
[
0
]);
usage
(
argv
[
0
]);
if
(
load_policy
(
policy
,
&
policydb
,
&
pf
))
if
(
load_policy
(
policy
,
&
policydb
,
&
pf
))
...
@@ -479,7 +933,10 @@ int main(int argc, char **argv)
...
@@ -479,7 +933,10 @@ int main(int argc, char **argv)
if
(
permissive
)
if
(
permissive
)
list_permissive
(
&
policydb
);
list_permissive
(
&
policydb
);
if
(
neverallows
)
rc
|=
check_neverallows
(
&
policydb
,
neverallows
);
policydb_destroy
(
&
policydb
);
policydb_destroy
(
&
policydb
);
return
0
;
return
rc
;
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment