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
8dbf9375
Commit
8dbf9375
authored
Mar 17, 2022
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Reorganize magiskinit code
parent
e266a811
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
178 additions
and
170 deletions
+178
-170
Android.mk
native/jni/Android.mk
+1
-0
mount.cpp
native/jni/init/mount.cpp
+0
-21
rootdir.cpp
native/jni/init/rootdir.cpp
+21
-149
selinux.cpp
native/jni/init/selinux.cpp
+156
-0
No files found.
native/jni/Android.mk
View file @
8dbf9375
...
...
@@ -63,6 +63,7 @@ LOCAL_SRC_FILES := \
init/rootdir.cpp \
init/getinfo.cpp \
init/twostage.cpp \
init/selinux.cpp \
magiskpolicy/sepolicy.cpp \
magiskpolicy/magiskpolicy.cpp \
magiskpolicy/rules.cpp \
...
...
native/jni/init/mount.cpp
View file @
8dbf9375
...
...
@@ -205,27 +205,6 @@ success:
xsymlink
(
custom_rules_dir
.
data
(),
path
);
}
void
RootFSInit
::
prepare
()
{
self
=
mmap_data
(
"/init"
);
magisk_cfg
=
mmap_data
(
"/.backup/.magisk"
);
LOGD
(
"Restoring /init
\n
"
);
rename
(
backup_init
(),
"/init"
);
}
void
SARBase
::
backup_files
()
{
if
(
access
(
"/overlay.d"
,
F_OK
)
==
0
)
backup_folder
(
"/overlay.d"
,
overlays
);
else
if
(
access
(
"/data/overlay.d"
,
F_OK
)
==
0
)
backup_folder
(
"/data/overlay.d"
,
overlays
);
self
=
mmap_data
(
"/proc/self/exe"
);
if
(
access
(
"/.backup/.magisk"
,
R_OK
)
==
0
)
magisk_cfg
=
mmap_data
(
"/.backup/.magisk"
);
else
if
(
access
(
"/data/.backup/.magisk"
,
R_OK
)
==
0
)
magisk_cfg
=
mmap_data
(
"/data/.backup/.magisk"
);
}
bool
LegacySARInit
::
mount_system_root
()
{
backup_files
();
...
...
native/jni/init/rootdir.cpp
View file @
8dbf9375
...
...
@@ -2,9 +2,7 @@
#include <libgen.h>
#include <magisk.hpp>
#include <magiskpolicy.hpp>
#include <utils.hpp>
#include <stream.hpp>
#include "init.hpp"
#include "magiskrc.inc"
...
...
@@ -82,153 +80,6 @@ static void load_overlay_rc(const char *overlay) {
}
}
void
MagiskInit
::
patch_sepolicy
(
const
char
*
file
)
{
LOGD
(
"Patching monolithic policy
\n
"
);
auto
sepol
=
unique_ptr
<
sepolicy
>
(
sepolicy
::
from_file
(
"/sepolicy"
));
sepol
->
magisk_rules
();
// Custom rules
if
(
!
custom_rules_dir
.
empty
())
{
if
(
auto
dir
=
xopen_dir
(
custom_rules_dir
.
data
()))
{
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
auto
rule
=
custom_rules_dir
+
"/"
+
entry
->
d_name
+
"/sepolicy.rule"
;
if
(
xaccess
(
rule
.
data
(),
R_OK
)
==
0
)
{
LOGD
(
"Loading custom sepolicy patch: [%s]
\n
"
,
rule
.
data
());
sepol
->
load_rule_file
(
rule
.
data
());
}
}
}
}
LOGD
(
"Dumping sepolicy to: [%s]
\n
"
,
file
);
sepol
->
to_file
(
file
);
// Remove OnePlus stupid debug sepolicy and use our own
if
(
access
(
"/sepolicy_debug"
,
F_OK
)
==
0
)
{
unlink
(
"/sepolicy_debug"
);
link
(
"/sepolicy"
,
"/sepolicy_debug"
);
}
}
#define MOCK_LOAD SELINUXMOCK "/load"
#define MOCK_ENFORCE SELINUXMOCK "/enforce"
#define MOCK_COMPAT SELINUXMOCK "/compatible"
#define REAL_SELINUXFS SELINUXMOCK "/fs"
void
MagiskInit
::
hijack_sepolicy
()
{
// Read all custom rules into memory
string
rules
;
if
(
!
custom_rules_dir
.
empty
())
{
if
(
auto
dir
=
xopen_dir
(
custom_rules_dir
.
data
()))
{
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
auto
rule_file
=
custom_rules_dir
+
"/"
+
entry
->
d_name
+
"/sepolicy.rule"
;
if
(
xaccess
(
rule_file
.
data
(),
R_OK
)
==
0
)
{
LOGD
(
"Load custom sepolicy patch: [%s]
\n
"
,
rule_file
.
data
());
full_read
(
rule_file
.
data
(),
rules
);
rules
+=
'\n'
;
}
}
}
}
// Hijack the "load" and "enforce" node in selinuxfs to manipulate
// the actual sepolicy being loaded into the kernel
xmkdir
(
SELINUXMOCK
,
0
);
auto
hijack
=
[]
{
LOGD
(
"Hijack ["
SELINUX_LOAD
"] and ["
SELINUX_ENFORCE
"]
\n
"
);
mkfifo
(
MOCK_LOAD
,
0600
);
mkfifo
(
MOCK_ENFORCE
,
0644
);
xmount
(
MOCK_LOAD
,
SELINUX_LOAD
,
nullptr
,
MS_BIND
,
nullptr
);
xmount
(
MOCK_ENFORCE
,
SELINUX_ENFORCE
,
nullptr
,
MS_BIND
,
nullptr
);
};
string
dt_compat
;
if
(
access
(
SELINUX_ENFORCE
,
F_OK
)
!=
0
)
{
// selinuxfs not mounted yet. Hijack the dt fstab nodes first
// and let the original init mount selinuxfs for us
// This only happens on Android 8.0 - 9.0
// Preserve sysfs and procfs for hijacking
mount_list
.
erase
(
std
::
remove_if
(
mount_list
.
begin
(),
mount_list
.
end
(),
[](
const
string
&
s
)
{
return
s
==
"/proc"
||
s
==
"/sys"
;
}),
mount_list
.
end
());
// Remount procfs with proper options
xmount
(
nullptr
,
"/proc"
,
nullptr
,
MS_REMOUNT
,
"hidepid=2,gid=3009"
);
char
buf
[
4096
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s/fstab/compatible"
,
config
->
dt_dir
);
dt_compat
=
full_read
(
buf
);
LOGD
(
"Hijack [%s]
\n
"
,
buf
);
mkfifo
(
MOCK_COMPAT
,
0444
);
xmount
(
MOCK_COMPAT
,
buf
,
nullptr
,
MS_BIND
,
nullptr
);
}
else
{
hijack
();
}
// Create a new process waiting for init operations
if
(
xfork
())
{
// In parent, return and continue boot process
return
;
}
if
(
!
dt_compat
.
empty
())
{
// This open will block until init calls DoFirstStageMount
// The only purpose here is actually to wait for init to mount selinuxfs for us
int
fd
=
xopen
(
MOCK_COMPAT
,
O_WRONLY
);
char
buf
[
4096
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s/fstab/compatible"
,
config
->
dt_dir
);
xumount2
(
buf
,
MNT_DETACH
);
hijack
();
xwrite
(
fd
,
dt_compat
.
data
(),
dt_compat
.
size
());
close
(
fd
);
}
// Read full sepolicy
int
fd
=
xopen
(
MOCK_LOAD
,
O_RDONLY
);
string
policy
=
fd_full_read
(
fd
);
close
(
fd
);
auto
sepol
=
unique_ptr
<
sepolicy
>
(
sepolicy
::
from_data
(
policy
.
data
(),
policy
.
length
()));
sepol
->
magisk_rules
();
sepol
->
load_rules
(
rules
);
// Mount selinuxfs to another path
xmkdir
(
REAL_SELINUXFS
,
0755
);
xmount
(
"selinuxfs"
,
REAL_SELINUXFS
,
"selinuxfs"
,
0
,
nullptr
);
// This open will block until init calls security_getenforce
fd
=
xopen
(
MOCK_ENFORCE
,
O_WRONLY
);
// Cleanup the hijacks
umount2
(
"/init"
,
MNT_DETACH
);
xumount2
(
SELINUX_LOAD
,
MNT_DETACH
);
xumount2
(
SELINUX_ENFORCE
,
MNT_DETACH
);
// Load patched policy
sepol
->
to_file
(
REAL_SELINUXFS
"/load"
);
// Write to mock "enforce" ONLY after sepolicy is loaded. We need to make sure
// the actual init process is blocked until sepolicy is loaded, or else
// restorecon will fail and re-exec won't change context, causing boot failure.
// We (ab)use the fact that security_getenforce reads the "enforce" file, and
// because it has been replaced with our FIFO file, init will block until we
// write something into the pipe, effectively hijacking its control flow.
xwrite
(
fd
,
"0"
,
1
);
close
(
fd
);
// At this point, the init process will be unblocked
// and continue on with restorecon + re-exec.
// Terminate process
exit
(
0
);
}
static
void
recreate_sbin
(
const
char
*
mirror
,
bool
use_bind_mount
)
{
auto
dp
=
xopen_dir
(
mirror
);
int
src
=
dirfd
(
dp
.
get
());
...
...
@@ -288,6 +139,19 @@ static void patch_socket_name(const char *path) {
bin
.
patch
({
make_pair
(
MAIN_SOCKET
,
rstr
)
});
}
void
SARBase
::
backup_files
()
{
if
(
access
(
"/overlay.d"
,
F_OK
)
==
0
)
backup_folder
(
"/overlay.d"
,
overlays
);
else
if
(
access
(
"/data/overlay.d"
,
F_OK
)
==
0
)
backup_folder
(
"/data/overlay.d"
,
overlays
);
self
=
mmap_data
(
"/proc/self/exe"
);
if
(
access
(
"/.backup/.magisk"
,
R_OK
)
==
0
)
magisk_cfg
=
mmap_data
(
"/.backup/.magisk"
);
else
if
(
access
(
"/data/.backup/.magisk"
,
R_OK
)
==
0
)
magisk_cfg
=
mmap_data
(
"/data/.backup/.magisk"
);
}
#define ROOTMIR MIRRDIR "/system_root"
#define NEW_INITRC "/system/etc/init/hw/init.rc"
...
...
@@ -380,6 +244,14 @@ void SARBase::patch_ro_root() {
chdir
(
"/"
);
}
void
RootFSInit
::
prepare
()
{
self
=
mmap_data
(
"/init"
);
magisk_cfg
=
mmap_data
(
"/.backup/.magisk"
);
LOGD
(
"Restoring /init
\n
"
);
rename
(
backup_init
(),
"/init"
);
}
#define PRE_TMPDIR "/magisk-tmp"
void
MagiskInit
::
patch_rw_root
()
{
...
...
native/jni/init/selinux.cpp
0 → 100644
View file @
8dbf9375
#include <sys/mount.h>
#include <magisk.hpp>
#include <magiskpolicy.hpp>
#include <utils.hpp>
#include "init.hpp"
using
namespace
std
;
void
MagiskInit
::
patch_sepolicy
(
const
char
*
file
)
{
LOGD
(
"Patching monolithic policy
\n
"
);
auto
sepol
=
unique_ptr
<
sepolicy
>
(
sepolicy
::
from_file
(
"/sepolicy"
));
sepol
->
magisk_rules
();
// Custom rules
if
(
!
custom_rules_dir
.
empty
())
{
if
(
auto
dir
=
xopen_dir
(
custom_rules_dir
.
data
()))
{
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
auto
rule
=
custom_rules_dir
+
"/"
+
entry
->
d_name
+
"/sepolicy.rule"
;
if
(
xaccess
(
rule
.
data
(),
R_OK
)
==
0
)
{
LOGD
(
"Loading custom sepolicy patch: [%s]
\n
"
,
rule
.
data
());
sepol
->
load_rule_file
(
rule
.
data
());
}
}
}
}
LOGD
(
"Dumping sepolicy to: [%s]
\n
"
,
file
);
sepol
->
to_file
(
file
);
// Remove OnePlus stupid debug sepolicy and use our own
if
(
access
(
"/sepolicy_debug"
,
F_OK
)
==
0
)
{
unlink
(
"/sepolicy_debug"
);
link
(
"/sepolicy"
,
"/sepolicy_debug"
);
}
}
#define MOCK_LOAD SELINUXMOCK "/load"
#define MOCK_ENFORCE SELINUXMOCK "/enforce"
#define MOCK_COMPAT SELINUXMOCK "/compatible"
#define REAL_SELINUXFS SELINUXMOCK "/fs"
void
MagiskInit
::
hijack_sepolicy
()
{
// Read all custom rules into memory
string
rules
;
if
(
!
custom_rules_dir
.
empty
())
{
if
(
auto
dir
=
xopen_dir
(
custom_rules_dir
.
data
()))
{
for
(
dirent
*
entry
;
(
entry
=
xreaddir
(
dir
.
get
()));)
{
auto
rule_file
=
custom_rules_dir
+
"/"
+
entry
->
d_name
+
"/sepolicy.rule"
;
if
(
xaccess
(
rule_file
.
data
(),
R_OK
)
==
0
)
{
LOGD
(
"Load custom sepolicy patch: [%s]
\n
"
,
rule_file
.
data
());
full_read
(
rule_file
.
data
(),
rules
);
rules
+=
'\n'
;
}
}
}
}
// Hijack the "load" and "enforce" node in selinuxfs to manipulate
// the actual sepolicy being loaded into the kernel
xmkdir
(
SELINUXMOCK
,
0
);
auto
hijack
=
[]
{
LOGD
(
"Hijack ["
SELINUX_LOAD
"] and ["
SELINUX_ENFORCE
"]
\n
"
);
mkfifo
(
MOCK_LOAD
,
0600
);
mkfifo
(
MOCK_ENFORCE
,
0644
);
xmount
(
MOCK_LOAD
,
SELINUX_LOAD
,
nullptr
,
MS_BIND
,
nullptr
);
xmount
(
MOCK_ENFORCE
,
SELINUX_ENFORCE
,
nullptr
,
MS_BIND
,
nullptr
);
};
string
dt_compat
;
if
(
access
(
SELINUX_ENFORCE
,
F_OK
)
!=
0
)
{
// selinuxfs not mounted yet. Hijack the dt fstab nodes first
// and let the original init mount selinuxfs for us
// This only happens on Android 8.0 - 9.0
// Preserve sysfs and procfs for hijacking
mount_list
.
erase
(
std
::
remove_if
(
mount_list
.
begin
(),
mount_list
.
end
(),
[](
const
string
&
s
)
{
return
s
==
"/proc"
||
s
==
"/sys"
;
}),
mount_list
.
end
());
// Remount procfs with proper options
xmount
(
nullptr
,
"/proc"
,
nullptr
,
MS_REMOUNT
,
"hidepid=2,gid=3009"
);
char
buf
[
4096
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s/fstab/compatible"
,
config
->
dt_dir
);
dt_compat
=
full_read
(
buf
);
LOGD
(
"Hijack [%s]
\n
"
,
buf
);
mkfifo
(
MOCK_COMPAT
,
0444
);
xmount
(
MOCK_COMPAT
,
buf
,
nullptr
,
MS_BIND
,
nullptr
);
}
else
{
hijack
();
}
// Create a new process waiting for init operations
if
(
xfork
())
{
// In parent, return and continue boot process
return
;
}
if
(
!
dt_compat
.
empty
())
{
// This open will block until init calls DoFirstStageMount
// The only purpose here is actually to wait for init to mount selinuxfs for us
int
fd
=
xopen
(
MOCK_COMPAT
,
O_WRONLY
);
char
buf
[
4096
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s/fstab/compatible"
,
config
->
dt_dir
);
xumount2
(
buf
,
MNT_DETACH
);
hijack
();
xwrite
(
fd
,
dt_compat
.
data
(),
dt_compat
.
size
());
close
(
fd
);
}
// Read full sepolicy
int
fd
=
xopen
(
MOCK_LOAD
,
O_RDONLY
);
string
policy
=
fd_full_read
(
fd
);
close
(
fd
);
auto
sepol
=
unique_ptr
<
sepolicy
>
(
sepolicy
::
from_data
(
policy
.
data
(),
policy
.
length
()));
sepol
->
magisk_rules
();
sepol
->
load_rules
(
rules
);
// Mount selinuxfs to another path
xmkdir
(
REAL_SELINUXFS
,
0755
);
xmount
(
"selinuxfs"
,
REAL_SELINUXFS
,
"selinuxfs"
,
0
,
nullptr
);
// This open will block until init calls security_getenforce
fd
=
xopen
(
MOCK_ENFORCE
,
O_WRONLY
);
// Cleanup the hijacks
umount2
(
"/init"
,
MNT_DETACH
);
xumount2
(
SELINUX_LOAD
,
MNT_DETACH
);
xumount2
(
SELINUX_ENFORCE
,
MNT_DETACH
);
// Load patched policy
sepol
->
to_file
(
REAL_SELINUXFS
"/load"
);
// Write to mock "enforce" ONLY after sepolicy is loaded. We need to make sure
// the actual init process is blocked until sepolicy is loaded, or else
// restorecon will fail and re-exec won't change context, causing boot failure.
// We (ab)use the fact that security_getenforce reads the "enforce" file, and
// because it has been replaced with our FIFO file, init will block until we
// write something into the pipe, effectively hijacking its control flow.
xwrite
(
fd
,
"0"
,
1
);
close
(
fd
);
// At this point, the init process will be unblocked
// and continue on with restorecon + re-exec.
// Terminate process
exit
(
0
);
}
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