Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
490e6a6f
Commit
490e6a6f
authored
Dec 09, 2019
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new API to load sepolicy rule file
parent
08177c3d
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
483 additions
and
446 deletions
+483
-446
Android.mk
native/jni/Android.mk
+2
-1
magiskpolicy.h
native/jni/include/magiskpolicy.h
+5
-3
api.cpp
native/jni/magiskpolicy/api.cpp
+2
-1
magiskpolicy.cpp
native/jni/magiskpolicy/magiskpolicy.cpp
+47
-439
policydb.cpp
native/jni/magiskpolicy/policydb.cpp
+1
-1
rules.cpp
native/jni/magiskpolicy/rules.cpp
+1
-1
statement.cpp
native/jni/magiskpolicy/statement.cpp
+425
-0
No files found.
native/jni/Android.mk
View file @
490e6a6f
...
@@ -73,6 +73,7 @@ LOCAL_SRC_FILES := \
...
@@ -73,6 +73,7 @@ LOCAL_SRC_FILES := \
magiskpolicy/magiskpolicy.cpp \
magiskpolicy/magiskpolicy.cpp \
magiskpolicy/rules.cpp \
magiskpolicy/rules.cpp \
magiskpolicy/policydb.cpp \
magiskpolicy/policydb.cpp \
magiskpolicy/statement.cpp \
magiskpolicy/sepolicy.c
magiskpolicy/sepolicy.c
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
LOCAL_CFLAGS := -DAPPLET_STUB_MAIN=magiskpolicy_main
...
@@ -97,7 +98,6 @@ ifdef BB_INIT
...
@@ -97,7 +98,6 @@ ifdef BB_INIT
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
LOCAL_STATIC_LIBRARIES := libsepol libxz libutils
LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES := \
jni/include \
jni/include \
jni/magiskpolicy \
$(EXT_PATH)/include \
$(EXT_PATH)/include \
out \
out \
out/$(TARGET_ARCH_ABI) \
out/$(TARGET_ARCH_ABI) \
...
@@ -113,6 +113,7 @@ LOCAL_SRC_FILES := \
...
@@ -113,6 +113,7 @@ LOCAL_SRC_FILES := \
magiskpolicy/magiskpolicy.cpp \
magiskpolicy/magiskpolicy.cpp \
magiskpolicy/rules.cpp \
magiskpolicy/rules.cpp \
magiskpolicy/policydb.cpp \
magiskpolicy/policydb.cpp \
magiskpolicy/statement.cpp \
magiskpolicy/sepolicy.c
magiskpolicy/sepolicy.c
LOCAL_LDFLAGS := -static
LOCAL_LDFLAGS := -static
...
...
native/jni/
magiskpolicy
/magiskpolicy.h
→
native/jni/
include
/magiskpolicy.h
View file @
490e6a6f
/* magiskpolicy.h - Public API for policy patching
*/
#pragma once
#pragma once
#include <stdlib.h>
#include <stdlib.h>
...
@@ -35,3 +32,8 @@ int sepol_exists(const char *source);
...
@@ -35,3 +32,8 @@ int sepol_exists(const char *source);
// Built in rules
// Built in rules
void
sepol_magisk_rules
();
void
sepol_magisk_rules
();
// Statement parsing
void
parse_statement
(
const
char
*
statement
);
void
load_rule_file
(
const
char
*
file
);
void
statement_help
();
native/jni/magiskpolicy/api.cpp
View file @
490e6a6f
#include "magiskpolicy.h"
#include <magiskpolicy.h>
#include "sepolicy.h"
#include "sepolicy.h"
//#define vprint(fmt, ...) printf(fmt, __VA_ARGS__)
//#define vprint(fmt, ...) printf(fmt, __VA_ARGS__)
...
...
native/jni/magiskpolicy/magiskpolicy.cpp
View file @
490e6a6f
/* magiskpolicy.cpp - Main function for policy patching
*
* Includes all the parsing logic for the policy statements
*/
#include <stdio.h>
#include <stdio.h>
#include <limits.h>
#include <limits.h>
#include <vector>
#include <string>
#include <logging.h>
#include <logging.h>
#include <utils.h>
#include <utils.h>
#include <flags.h>
#include <flags.h>
#include <magiskpolicy.h>
#include "sepolicy.h"
#include "sepolicy.h"
#include "magiskpolicy.h"
using
namespace
std
;
static
const
char
*
type_msg_1
=
"Type 1:
\n
"
"
\"
<rule_name> source_type target_type class perm_set
\"\n
"
"Rules: allow, deny, auditallow, dontaudit
\n
"
;
static
const
char
*
type_msg_2
=
"Type 2:
\n
"
"
\"
<rule_name> source_type target_type class operation xperm_set
\"\n
"
"Rules: allowxperm, auditallowxperm, dontauditxperm
\n
"
"* The only supported operation is ioctl
\n
"
"* The only supported xperm_set format is range ([low-high])
\n
"
;
static
const
char
*
type_msg_3
=
"Type 3:
\n
"
"
\"
<rule_name> class
\"\n
"
"Rules: create, permissive, enforcing
\n
"
;
static
const
char
*
type_msg_4
=
"Type 4:
\n
"
"
\"
attradd class attribute
\"\n
"
;
static
const
char
*
type_msg_5
=
"Type 5:
\n
"
"
\"
<rule_name> source_type target_type class default_type
\"\n
"
"Rules: type_transition, type_change, type_member
\n
"
;
static
const
char
*
type_msg_6
=
using
namespace
std
::
literals
;
"Type 6:
\n
"
"
\"
name_transition source_type target_type class default_type object_name
\"\n
"
;
[[
noreturn
]]
static
void
statements
()
{
fprintf
(
stderr
,
"One policy statement should be treated as one parameter;
\n
"
"this means a full policy statement should be enclosed in quotes;
\n
"
"multiple policy statements can be provided in a single command
\n
"
"
\n
"
"The statements has a format of
\"
<rule_name> [args...]
\"\n
"
"Multiple types and permissions can be grouped into collections
\n
"
"wrapped in curly brackets.
\n
"
"'*' represents a collection containing all valid matches.
\n
"
"
\n
"
"Supported policy statements:
\n
"
"
\n
"
"%s
\n
"
"%s
\n
"
"%s
\n
"
"%s
\n
"
"%s
\n
"
"%s
\n
"
"Notes:
\n
"
"* Type 4 - 6 does not support collections
\n
"
"* Object classes cannot be collections
\n
"
"* source_type and target_type can also be attributes
\n
"
"
\n
"
"Example: allow { s1 s2 } { t1 t2 } class *
\n
"
"Will be expanded to:
\n
"
"
\n
"
"allow s1 t1 class { all permissions }
\n
"
"allow s1 t2 class { all permissions }
\n
"
"allow s2 t1 class { all permissions }
\n
"
"allow s2 t2 class { all permissions }
\n
"
"
\n
"
,
type_msg_1
,
type_msg_2
,
type_msg_3
,
type_msg_4
,
type_msg_5
,
type_msg_6
);
exit
(
0
);
}
[[
noreturn
]]
static
void
usage
(
char
*
arg0
)
{
[[
noreturn
]]
static
void
usage
(
char
*
arg0
)
{
fprintf
(
stderr
,
fprintf
(
stderr
,
FULL_VER
(
MagiskPolicy
)
"
\n\n
"
FULL_VER
(
MagiskPolicy
)
R"EOF(
"Usage: %s [--options...] [policy statements...]
\n
"
"
\n
"
Usage: %s [--options...] [policy statements...]
"Options:
\n
"
" --help show help message for policy statements
\n
"
Options:
" --load FILE load policies from FILE
\n
"
--help show help message for policy statements
" --load-split load from preloaded sepolicy or compile
\n
"
--load FILE load policies from FILE
" split policies
\n
"
--load-split load from precompiled sepolicy or compile
" --compile-split compile split cil policies
\n
"
split policies
" --save FILE save policies to FILE
\n
"
--compile-split compile split cil policies
" --live directly apply sepolicy live
\n
"
--save FILE save policies to FILE
" --magisk inject built-in rules for a minimal
\n
"
--live directly apply sepolicy live
" Magisk selinux environment
\n
"
--magisk inject built-in rules for a minimal
"
\n
"
Magisk selinux environment
"If neither --load or --compile-split is specified, it will load
\n
"
--apply FILE apply rules from FILE, read and parsed
"from current live policies ("
SELINUX_POLICY
")
\n
"
line by line as policy statements
"
\n
"
,
arg0
);
If neither --load or --compile-split is specified, it will load
from current live policies (/sys/fs/selinux/policy)
)EOF"
,
arg0
);
exit
(
1
);
exit
(
1
);
}
}
static
int
parse_bracket
(
char
*
tok
,
char
*&
stmt
,
vector
<
const
char
*>
*
vec
)
{
if
(
tok
==
nullptr
||
tok
[
0
]
!=
'{'
)
{
// Not in a bracket
vec
->
push_back
(
tok
);
}
else
{
if
(
stmt
)
stmt
[
-
1
]
=
' '
;
tok
=
strchr
(
tok
,
'{'
)
+
1
;
char
*
end
=
strchr
(
tok
,
'}'
);
if
(
end
==
nullptr
)
// Bracket not closed
return
1
;
*
end
=
'\0'
;
char
*
cur
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
tok
))
!=
nullptr
)
vec
->
push_back
(
cur
);
stmt
=
end
+
1
;
}
return
0
;
}
// Pattern 1: action { source } { target } class { permission }
static
int
parse_pattern_1
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_allow
;
break
;
case
1
:
action_func
=
sepol_deny
;
break
;
case
2
:
action_func
=
sepol_auditallow
;
break
;
case
3
:
action_func
=
sepol_dontaudit
;
break
;
default
:
return
1
;
}
int
state
=
0
;
char
*
cur
,
*
cls
;
vector
<
const
char
*>
source
,
target
,
permission
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
source
;
break
;
case
1
:
vec
=
&
target
;
break
;
case
2
:
vec
=
nullptr
;
cls
=
cur
;
break
;
case
3
:
vec
=
&
permission
;
break
;
default
:
return
1
;
}
if
(
vec
&&
parse_bracket
(
cur
,
stmt
,
vec
))
return
1
;
++
state
;
}
if
(
state
!=
4
||
source
.
empty
()
||
target
.
empty
()
||
permission
.
empty
())
return
1
;
for
(
auto
src
:
source
)
for
(
auto
tgt
:
target
)
for
(
auto
perm
:
permission
)
if
(
action_func
(
src
,
tgt
,
cls
,
perm
))
fprintf
(
stderr
,
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
src
,
tgt
,
cls
,
perm
);
return
0
;
}
// Pattern 2: action { source } { target } { class } ioctl range
static
int
parse_pattern_2
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_allowxperm
;
break
;
case
1
:
action_func
=
sepol_auditallowxperm
;
break
;
case
2
:
action_func
=
sepol_dontauditxperm
;
break
;
default
:
return
1
;
}
int
state
=
0
;
char
*
cur
,
*
range
;
vector
<
const
char
*>
source
,
target
,
classes
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
source
;
break
;
case
1
:
vec
=
&
target
;
break
;
case
2
:
vec
=
&
classes
;
break
;
case
3
:
// Currently only support ioctl
if
(
strcmp
(
cur
,
"ioctl"
)
!=
0
)
return
1
;
vec
=
nullptr
;
break
;
case
4
:
vec
=
nullptr
;
range
=
cur
;
break
;
default
:
return
1
;
}
if
(
vec
&&
parse_bracket
(
cur
,
stmt
,
vec
))
return
1
;
++
state
;
}
if
(
state
!=
5
||
source
.
empty
()
||
target
.
empty
()
||
classes
.
empty
())
return
1
;
for
(
auto
src
:
source
)
for
(
auto
tgt
:
target
)
for
(
auto
cls
:
classes
)
if
(
action_func
(
src
,
tgt
,
cls
,
range
))
fprintf
(
stderr
,
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
src
,
tgt
,
cls
,
range
);
return
0
;
}
// Pattern 3: action { type }
static
int
parse_pattern_3
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_create
;
break
;
case
1
:
action_func
=
sepol_permissive
;
break
;
case
2
:
action_func
=
sepol_enforce
;
break
;
default
:
return
1
;
}
char
*
cur
;
vector
<
const
char
*>
domains
;
while
((
cur
=
strtok_r
(
nullptr
,
" {}"
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
domains
.
push_back
(
cur
);
}
if
(
domains
.
empty
())
return
1
;
for
(
auto
dom
:
domains
)
if
(
action_func
(
dom
))
fprintf
(
stderr
,
"Error in: %s %s
\n
"
,
action_str
,
dom
);
return
0
;
}
// Pattern 4: action { class } { attribute }
static
int
parse_pattern_4
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_attradd
;
break
;
default
:
return
1
;
}
int
state
=
0
;
char
*
cur
;
vector
<
const
char
*>
classes
,
attribute
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
classes
;
break
;
case
1
:
vec
=
&
attribute
;
break
;
default
:
return
1
;
}
if
(
parse_bracket
(
cur
,
stmt
,
vec
))
return
1
;
++
state
;
}
if
(
state
!=
2
||
classes
.
empty
()
||
attribute
.
empty
())
return
1
;
for
(
auto
cls
:
classes
)
for
(
auto
attr
:
attribute
)
if
(
action_func
(
cls
,
attr
))
fprintf
(
stderr
,
"Error in: %s %s %s
\n
"
,
action_str
,
cls
,
attr
);
return
0
;
}
// Pattern 5: action source target class default
static
int
parse_pattern_5
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_typetrans
;
break
;
case
1
:
action_func
=
sepol_typechange
;
break
;
case
2
:
action_func
=
sepol_typemember
;
break
;
default
:
return
1
;
}
int
state
=
0
;
char
*
cur
;
char
*
source
,
*
target
,
*
cls
,
*
def
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
switch
(
state
)
{
case
0
:
source
=
cur
;
break
;
case
1
:
target
=
cur
;
break
;
case
2
:
cls
=
cur
;
break
;
case
3
:
def
=
cur
;
break
;
default
:
return
1
;
}
++
state
;
}
if
(
state
<
4
)
return
1
;
if
(
action_func
(
source
,
target
,
cls
,
def
))
fprintf
(
stderr
,
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
source
,
target
,
cls
,
def
);
return
0
;
}
// Pattern 6: action source target class default filename
static
int
parse_pattern_6
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
state
=
0
;
char
*
cur
;
char
*
source
,
*
target
,
*
cls
,
*
def
,
*
filename
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
switch
(
state
)
{
case
0
:
source
=
cur
;
break
;
case
1
:
target
=
cur
;
break
;
case
2
:
cls
=
cur
;
break
;
case
3
:
def
=
cur
;
break
;
case
4
:
filename
=
cur
;
break
;
default
:
return
1
;
}
++
state
;
}
if
(
state
<
4
)
return
1
;
if
(
sepol_nametrans
(
source
,
target
,
cls
,
def
,
filename
))
fprintf
(
stderr
,
"Error in: %s %s %s %s %s %s
\n
"
,
action_str
,
source
,
target
,
cls
,
def
,
filename
);
return
0
;
}
#define add_action(name, type, num) \
else if (strcmp(name, action) == 0) { \
if (parse_pattern_##type(num, name, remain)) \
fprintf(stderr, "Syntax error in '%s'\n\n%s\n", orig.c_str(), type_msg_##type); \
}
static
void
parse_statement
(
char
*
statement
)
{
char
*
action
,
*
remain
;
// strtok will modify the origin string, duplicate the statement for error messages
string
orig
(
statement
);
action
=
strtok_r
(
statement
,
" "
,
&
remain
);
if
(
remain
==
nullptr
)
remain
=
&
action
[
strlen
(
action
)];
if
(
0
)
{}
add_action
(
"allow"
,
1
,
0
)
add_action
(
"deny"
,
1
,
1
)
add_action
(
"auditallow"
,
1
,
2
)
add_action
(
"dontaudit"
,
1
,
3
)
add_action
(
"allowxperm"
,
2
,
0
)
add_action
(
"auditallowxperm"
,
2
,
1
)
add_action
(
"dontauditxperm"
,
2
,
2
)
add_action
(
"create"
,
3
,
0
)
add_action
(
"permissive"
,
3
,
1
)
add_action
(
"enforce"
,
3
,
2
)
add_action
(
"attradd"
,
4
,
0
)
add_action
(
"type_transition"
,
5
,
0
)
add_action
(
"type_change"
,
5
,
1
)
add_action
(
"type_member"
,
5
,
2
)
add_action
(
"name_transition"
,
6
,
0
)
else
{
fprintf
(
stderr
,
"Unknown statement: '%s'
\n\n
"
,
orig
.
c_str
());
}
}
int
magiskpolicy_main
(
int
argc
,
char
*
argv
[])
{
int
magiskpolicy_main
(
int
argc
,
char
*
argv
[])
{
cmdline_logging
();
cmdline_logging
();
const
char
*
outfile
=
nullptr
;
const
char
*
out_file
=
nullptr
;
bool
magisk
=
false
,
live
=
false
;
const
char
*
rule_file
=
nullptr
;
bool
magisk
=
false
;
bool
live
=
false
;
if
(
argc
<
2
)
usage
(
argv
[
0
]);
if
(
argc
<
2
)
usage
(
argv
[
0
]);
int
i
=
1
;
int
i
=
1
;
for
(;
i
<
argc
;
++
i
)
{
for
(;
i
<
argc
;
++
i
)
{
// Parse options
// Parse options
if
(
argv
[
i
][
0
]
==
'-'
&&
argv
[
i
][
1
]
==
'-'
)
{
if
(
argv
[
i
][
0
]
==
'-'
&&
argv
[
i
][
1
]
==
'-'
)
{
if
(
strcmp
(
argv
[
i
]
+
2
,
"live"
)
==
0
)
auto
option
=
argv
[
i
]
+
2
;
if
(
option
==
"live"
sv
)
live
=
true
;
live
=
true
;
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"magisk"
)
==
0
)
else
if
(
option
==
"magisk"
sv
)
magisk
=
true
;
magisk
=
true
;
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"load"
)
==
0
)
{
else
if
(
option
==
"load"
sv
)
{
if
(
argv
[
i
+
1
]
==
nullptr
)
if
(
argv
[
i
+
1
]
==
nullptr
)
usage
(
argv
[
0
]);
usage
(
argv
[
0
]);
if
(
load_policydb
(
argv
[
i
+
1
]))
{
if
(
load_policydb
(
argv
[
i
+
1
]))
{
...
@@ -461,23 +61,28 @@ int magiskpolicy_main(int argc, char *argv[]) {
...
@@ -461,23 +61,28 @@ int magiskpolicy_main(int argc, char *argv[]) {
return
1
;
return
1
;
}
}
++
i
;
++
i
;
}
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"load-split"
)
==
0
)
{
}
else
if
(
option
==
"load-split"
sv
)
{
if
(
load_split_cil
())
{
if
(
load_split_cil
())
{
fprintf
(
stderr
,
"Cannot load split cil
\n
"
);
fprintf
(
stderr
,
"Cannot load split cil
\n
"
);
return
1
;
return
1
;
}
}
}
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"compile-split"
)
==
0
)
{
}
else
if
(
option
==
"compile-split"
sv
)
{
if
(
compile_split_cil
())
{
if
(
compile_split_cil
())
{
fprintf
(
stderr
,
"Cannot compile split cil
\n
"
);
fprintf
(
stderr
,
"Cannot compile split cil
\n
"
);
return
1
;
return
1
;
}
}
}
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"save"
)
==
0
)
{
}
else
if
(
option
==
"save"
sv
)
{
if
(
argv
[
i
+
1
]
==
nullptr
)
usage
(
argv
[
0
]);
out_file
=
argv
[
i
+
1
];
++
i
;
}
else
if
(
option
==
"apply"
sv
)
{
if
(
argv
[
i
+
1
]
==
nullptr
)
if
(
argv
[
i
+
1
]
==
nullptr
)
usage
(
argv
[
0
]);
usage
(
argv
[
0
]);
out
file
=
argv
[
i
+
1
];
rule_
file
=
argv
[
i
+
1
];
++
i
;
++
i
;
}
else
if
(
strcmp
(
argv
[
i
]
+
2
,
"help"
)
==
0
)
{
}
else
if
(
option
==
"help"
sv
)
{
statement
s
();
statement
_help
();
}
else
{
}
else
{
usage
(
argv
[
0
]);
usage
(
argv
[
0
]);
}
}
...
@@ -495,6 +100,9 @@ int magiskpolicy_main(int argc, char *argv[]) {
...
@@ -495,6 +100,9 @@ int magiskpolicy_main(int argc, char *argv[]) {
if
(
magisk
)
if
(
magisk
)
sepol_magisk_rules
();
sepol_magisk_rules
();
if
(
rule_file
)
load_rule_file
(
rule_file
);
for
(;
i
<
argc
;
++
i
)
for
(;
i
<
argc
;
++
i
)
parse_statement
(
argv
[
i
]);
parse_statement
(
argv
[
i
]);
...
@@ -503,8 +111,8 @@ int magiskpolicy_main(int argc, char *argv[]) {
...
@@ -503,8 +111,8 @@ int magiskpolicy_main(int argc, char *argv[]) {
return
1
;
return
1
;
}
}
if
(
out
file
&&
dump_policydb
(
out
file
))
{
if
(
out
_file
&&
dump_policydb
(
out_
file
))
{
fprintf
(
stderr
,
"Cannot dump policy to %s
\n
"
,
outfile
);
fprintf
(
stderr
,
"Cannot dump policy to %s
\n
"
,
out
_
file
);
return
1
;
return
1
;
}
}
...
...
native/jni/magiskpolicy/policydb.cpp
View file @
490e6a6f
...
@@ -8,8 +8,8 @@
...
@@ -8,8 +8,8 @@
#include <utils.h>
#include <utils.h>
#include <logging.h>
#include <logging.h>
#include <stream.h>
#include <stream.h>
#include <magiskpolicy.h>
#include "magiskpolicy.h"
#include "sepolicy.h"
#include "sepolicy.h"
int
load_policydb
(
const
char
*
file
)
{
int
load_policydb
(
const
char
*
file
)
{
...
...
native/jni/magiskpolicy/rules.cpp
View file @
490e6a6f
#include <logging.h>
#include <logging.h>
#include <flags.h>
#include <flags.h>
#include <magiskpolicy.h>
#include "magiskpolicy.h"
#include "sepolicy.h"
#include "sepolicy.h"
static
void
allowSuClient
(
const
char
*
target
)
{
static
void
allowSuClient
(
const
char
*
target
)
{
...
...
native/jni/magiskpolicy/statement.cpp
0 → 100644
View file @
490e6a6f
#include <cstring>
#include <vector>
#include <string>
#include <magiskpolicy.h>
#include <logging.h>
#include <utils.h>
using
namespace
std
;
static
const
char
*
type_msg_1
=
R"EOF(Type 1:
"<rule_name> source_type target_type class perm_set"
Rules: allow, deny, auditallow, dontaudit
)EOF"
;
static
const
char
*
type_msg_2
=
R"EOF(Type 2:
"<rule_name> source_type target_type class operation xperm_set"
Rules: allowxperm, auditallowxperm, dontauditxperm
* The only supported operation is ioctl
* The only supported xperm_set format is range ([low-high])
)EOF"
;
static
const
char
*
type_msg_3
=
R"EOF(Type 3:
"<rule_name> class"
Rules: create, permissive, enforcing
)EOF"
;
static
const
char
*
type_msg_4
=
R"EOF(Type 4:
"attradd class attribute"
)EOF"
;
static
const
char
*
type_msg_5
=
R"EOF(Type 5:
"<rule_name> source_type target_type class default_type"
Rules: type_transition, type_change, type_member
)EOF"
;
static
const
char
*
type_msg_6
=
R"EOF(Type 6:
"name_transition source_type target_type class default_type object_name"
)EOF"
;
void
statement_help
()
{
fprintf
(
stderr
,
R"EOF(One policy statement should be treated as one parameter;
this means a full policy statement should be enclosed in quotes.
Multiple policy statements can be provided in a single command.
The statements has a format of "<rule_name> [args...]"
Multiple types and permissions can be grouped into collections
wrapped in curly brackets.
'*' represents a collection containing all valid matches.
Supported policy statements:
%s
%s
%s
%s
%s
%s
Notes:
* Type 4 - 6 does not support collections
* Object classes cannot be collections
* source_type and target_type can also be attributes
Example: allow { s1 s2 } { t1 t2 } class *
Will be expanded to:
allow s1 t1 class { all-permissions }
allow s1 t2 class { all-permissions }
allow s2 t1 class { all-permissions }
allow s2 t2 class { all-permissions }
)EOF"
,
type_msg_1
,
type_msg_2
,
type_msg_3
,
type_msg_4
,
type_msg_5
,
type_msg_6
);
exit
(
0
);
}
static
int
parse_bracket
(
char
*
tok
,
char
*&
stmt
,
vector
<
const
char
*>
&
vec
)
{
if
(
tok
==
nullptr
||
tok
[
0
]
!=
'{'
)
{
// Not in a bracket
vec
.
push_back
(
tok
);
}
else
{
if
(
stmt
)
stmt
[
-
1
]
=
' '
;
tok
=
strchr
(
tok
,
'{'
)
+
1
;
char
*
end
=
strchr
(
tok
,
'}'
);
if
(
end
==
nullptr
)
// Bracket not closed
return
1
;
*
end
=
'\0'
;
char
*
cur
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
tok
))
!=
nullptr
)
vec
.
push_back
(
cur
);
stmt
=
end
+
1
;
}
return
0
;
}
// Pattern 1: action { source } { target } class { permission }
static
int
parse_pattern_1
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_allow
;
break
;
case
1
:
action_func
=
sepol_deny
;
break
;
case
2
:
action_func
=
sepol_auditallow
;
break
;
case
3
:
action_func
=
sepol_dontaudit
;
break
;
default:
return
1
;
}
int
state
=
0
;
char
*
cur
,
*
cls
;
vector
<
const
char
*>
source
,
target
,
permission
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
source
;
break
;
case
1
:
vec
=
&
target
;
break
;
case
2
:
vec
=
nullptr
;
cls
=
cur
;
break
;
case
3
:
vec
=
&
permission
;
break
;
default:
return
1
;
}
if
(
vec
&&
parse_bracket
(
cur
,
stmt
,
*
vec
))
return
1
;
++
state
;
}
if
(
state
!=
4
||
source
.
empty
()
||
target
.
empty
()
||
permission
.
empty
())
return
1
;
for
(
auto
src
:
source
)
for
(
auto
tgt
:
target
)
for
(
auto
perm
:
permission
)
if
(
action_func
(
src
,
tgt
,
cls
,
perm
))
LOGW
(
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
src
,
tgt
,
cls
,
perm
);
return
0
;
}
// Pattern 2: action { source } { target } { class } ioctl range
static
int
parse_pattern_2
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_allowxperm
;
break
;
case
1
:
action_func
=
sepol_auditallowxperm
;
break
;
case
2
:
action_func
=
sepol_dontauditxperm
;
break
;
default:
return
1
;
}
int
state
=
0
;
char
*
cur
,
*
range
;
vector
<
const
char
*>
source
,
target
,
classes
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
source
;
break
;
case
1
:
vec
=
&
target
;
break
;
case
2
:
vec
=
&
classes
;
break
;
case
3
:
// Currently only support ioctl
if
(
strcmp
(
cur
,
"ioctl"
)
!=
0
)
return
1
;
vec
=
nullptr
;
break
;
case
4
:
vec
=
nullptr
;
range
=
cur
;
break
;
default:
return
1
;
}
if
(
vec
&&
parse_bracket
(
cur
,
stmt
,
*
vec
))
return
1
;
++
state
;
}
if
(
state
!=
5
||
source
.
empty
()
||
target
.
empty
()
||
classes
.
empty
())
return
1
;
for
(
auto
src
:
source
)
for
(
auto
tgt
:
target
)
for
(
auto
cls
:
classes
)
if
(
action_func
(
src
,
tgt
,
cls
,
range
))
LOGW
(
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
src
,
tgt
,
cls
,
range
);
return
0
;
}
// Pattern 3: action { type }
static
int
parse_pattern_3
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_create
;
break
;
case
1
:
action_func
=
sepol_permissive
;
break
;
case
2
:
action_func
=
sepol_enforce
;
break
;
default:
return
1
;
}
char
*
cur
;
vector
<
const
char
*>
domains
;
while
((
cur
=
strtok_r
(
nullptr
,
" {}"
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
domains
.
push_back
(
cur
);
}
if
(
domains
.
empty
())
return
1
;
for
(
auto
dom
:
domains
)
if
(
action_func
(
dom
))
LOGW
(
"Error in: %s %s
\n
"
,
action_str
,
dom
);
return
0
;
}
// Pattern 4: action { class } { attribute }
static
int
parse_pattern_4
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_attradd
;
break
;
default:
return
1
;
}
int
state
=
0
;
char
*
cur
;
vector
<
const
char
*>
classes
,
attribute
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
if
(
cur
[
0
]
==
'*'
)
cur
=
ALL
;
vector
<
const
char
*>
*
vec
;
switch
(
state
)
{
case
0
:
vec
=
&
classes
;
break
;
case
1
:
vec
=
&
attribute
;
break
;
default:
return
1
;
}
if
(
parse_bracket
(
cur
,
stmt
,
*
vec
))
return
1
;
++
state
;
}
if
(
state
!=
2
||
classes
.
empty
()
||
attribute
.
empty
())
return
1
;
for
(
auto
cls
:
classes
)
for
(
auto
attr
:
attribute
)
if
(
action_func
(
cls
,
attr
))
LOGW
(
"Error in: %s %s %s
\n
"
,
action_str
,
cls
,
attr
);
return
0
;
}
// Pattern 5: action source target class default
static
int
parse_pattern_5
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
(
*
action_func
)(
const
char
*
,
const
char
*
,
const
char
*
,
const
char
*
);
switch
(
action
)
{
case
0
:
action_func
=
sepol_typetrans
;
break
;
case
1
:
action_func
=
sepol_typechange
;
break
;
case
2
:
action_func
=
sepol_typemember
;
break
;
default:
return
1
;
}
int
state
=
0
;
char
*
cur
;
char
*
source
,
*
target
,
*
cls
,
*
def
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
switch
(
state
)
{
case
0
:
source
=
cur
;
break
;
case
1
:
target
=
cur
;
break
;
case
2
:
cls
=
cur
;
break
;
case
3
:
def
=
cur
;
break
;
default:
return
1
;
}
++
state
;
}
if
(
state
<
4
)
return
1
;
if
(
action_func
(
source
,
target
,
cls
,
def
))
LOGW
(
"Error in: %s %s %s %s %s
\n
"
,
action_str
,
source
,
target
,
cls
,
def
);
return
0
;
}
// Pattern 6: action source target class default filename
static
int
parse_pattern_6
(
int
action
,
const
char
*
action_str
,
char
*
stmt
)
{
int
state
=
0
;
char
*
cur
;
char
*
source
,
*
target
,
*
cls
,
*
def
,
*
filename
;
while
((
cur
=
strtok_r
(
nullptr
,
" "
,
&
stmt
))
!=
nullptr
)
{
switch
(
state
)
{
case
0
:
source
=
cur
;
break
;
case
1
:
target
=
cur
;
break
;
case
2
:
cls
=
cur
;
break
;
case
3
:
def
=
cur
;
break
;
case
4
:
filename
=
cur
;
break
;
default:
return
1
;
}
++
state
;
}
if
(
state
<
4
)
return
1
;
if
(
sepol_nametrans
(
source
,
target
,
cls
,
def
,
filename
))
LOGW
(
"Error in: %s %s %s %s %s %s
\n
"
,
action_str
,
source
,
target
,
cls
,
def
,
filename
);
return
0
;
}
#define add_action(name, type, num) \
else if (strcmp(name, action) == 0) { \
if (parse_pattern_##type(num, name, remain)) \
LOGW("Syntax error in '%s'\n\n%s\n", statement, type_msg_##type); \
}
void
parse_statement
(
const
char
*
statement
)
{
char
*
action
,
*
remain
;
// strtok will modify strings, duplicate the statement
string
stmt
(
statement
);
action
=
strtok_r
(
stmt
.
data
(),
" "
,
&
remain
);
if
(
remain
==
nullptr
)
{
LOGE
(
"Syntax error in '%s'
\n\n
"
,
statement
);
return
;
}
if
(
0
)
{}
add_action
(
"allow"
,
1
,
0
)
add_action
(
"deny"
,
1
,
1
)
add_action
(
"auditallow"
,
1
,
2
)
add_action
(
"dontaudit"
,
1
,
3
)
add_action
(
"allowxperm"
,
2
,
0
)
add_action
(
"auditallowxperm"
,
2
,
1
)
add_action
(
"dontauditxperm"
,
2
,
2
)
add_action
(
"create"
,
3
,
0
)
add_action
(
"permissive"
,
3
,
1
)
add_action
(
"enforce"
,
3
,
2
)
add_action
(
"attradd"
,
4
,
0
)
add_action
(
"type_transition"
,
5
,
0
)
add_action
(
"type_change"
,
5
,
1
)
add_action
(
"type_member"
,
5
,
2
)
add_action
(
"name_transition"
,
6
,
0
)
else
{
LOGW
(
"Unknown statement: '%s'
\n\n
"
,
statement
);
}
}
void
load_rule_file
(
const
char
*
file
)
{
file_readline
(
file
,
[](
string_view
line
)
->
bool
{
if
(
line
.
empty
()
||
line
[
0
]
==
'#'
)
return
true
;
parse_statement
(
line
.
data
());
return
true
;
},
true
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment