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
2c400138
Commit
2c400138
authored
Jun 26, 2018
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Several adjustments
parent
caa39474
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
91 additions
and
123 deletions
+91
-123
su.c
su.c
+0
-37
su_daemon.c
su_daemon.c
+91
-86
No files found.
su.c
View file @
2c400138
...
@@ -22,7 +22,6 @@
...
@@ -22,7 +22,6 @@
#include <libgen.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/auxv.h>
#include <selinux/selinux.h>
#include <selinux/selinux.h>
#include "magisk.h"
#include "magisk.h"
...
@@ -160,42 +159,6 @@ __attribute__ ((noreturn)) void exit2(int status) {
...
@@ -160,42 +159,6 @@ __attribute__ ((noreturn)) void exit2(int status) {
}
}
int
su_daemon_main
(
int
argc
,
char
**
argv
)
{
int
su_daemon_main
(
int
argc
,
char
**
argv
)
{
// Sanitize all secure environment variables (from linker_environ.c in AOSP linker).
/* The same list than GLibc at this point */
static
const
char
*
const
unsec_vars
[]
=
{
"GCONV_PATH"
,
"GETCONF_DIR"
,
"HOSTALIASES"
,
"LD_AUDIT"
,
"LD_DEBUG"
,
"LD_DEBUG_OUTPUT"
,
"LD_DYNAMIC_WEAK"
,
"LD_LIBRARY_PATH"
,
"LD_ORIGIN_PATH"
,
"LD_PRELOAD"
,
"LD_PROFILE"
,
"LD_SHOW_AUXV"
,
"LD_USE_LOAD_BIAS"
,
"LOCALDOMAIN"
,
"LOCPATH"
,
"MALLOC_TRACE"
,
"MALLOC_CHECK_"
,
"NIS_PATH"
,
"NLSPATH"
,
"RESOLV_HOST_CONF"
,
"RES_OPTIONS"
,
"TMPDIR"
,
"TZDIR"
,
"LD_AOUT_LIBRARY_PATH"
,
"LD_AOUT_PRELOAD"
,
// not listed in linker, used due to system() call
"IFS"
,
NULL
};
if
(
getauxval
(
AT_SECURE
))
for
(
int
i
=
0
;
unsec_vars
[
i
];
++
i
)
unsetenv
(
unsec_vars
[
i
]);
int
c
,
socket_serv_fd
,
fd
;
int
c
,
socket_serv_fd
,
fd
;
char
result
[
64
];
char
result
[
64
];
struct
option
long_opts
[]
=
{
struct
option
long_opts
[]
=
{
...
...
su_daemon.c
View file @
2c400138
...
@@ -197,85 +197,8 @@ static struct su_info *get_su_info(unsigned uid) {
...
@@ -197,85 +197,8 @@ static struct su_info *get_su_info(unsigned uid) {
return
info
;
return
info
;
}
}
void
su_daemon_receiver
(
int
client
,
struct
ucred
*
credential
)
{
static
void
su_executor
(
int
client
)
{
LOGD
(
"su: request from client: %d
\n
"
,
client
);
LOGD
(
"su: executor started
\n
"
);
// Default values
struct
su_context
ctx
=
{
.
info
=
get_su_info
(
credential
->
uid
),
.
to
=
{
.
uid
=
UID_ROOT
,
.
login
=
0
,
.
keepenv
=
0
,
.
shell
=
DEFAULT_SHELL
,
.
command
=
NULL
,
},
.
pid
=
credential
->
pid
,
.
pipefd
=
{
-
1
,
-
1
}
};
// Fail fast
if
(
ctx
.
info
->
access
.
policy
==
DENY
&&
!
ctx
.
info
->
access
.
log
&&
!
ctx
.
info
->
access
.
notify
)
{
UNLOCK_UID
();
write_int
(
client
,
DENY
);
return
;
}
// If still not determined, open a pipe and wait for results
if
(
ctx
.
info
->
access
.
policy
==
QUERY
)
xpipe2
(
ctx
.
pipefd
,
O_CLOEXEC
);
/* Fork a new process, the child process will need to setsid,
* open a pseudo-terminal if needed, and will eventually run exec
* The parent process will wait for the result and
* send the return code back to our client
*/
int
child
=
xfork
();
if
(
child
)
{
// Wait for results
if
(
ctx
.
pipefd
[
0
]
>=
0
)
{
xxread
(
ctx
.
pipefd
[
0
],
&
ctx
.
info
->
access
.
policy
,
sizeof
(
policy_t
));
close
(
ctx
.
pipefd
[
0
]);
close
(
ctx
.
pipefd
[
1
]);
}
// The policy is determined, unlock
UNLOCK_UID
();
// Info is now useless to us, decrement reference count
--
ctx
.
info
->
ref
;
// Wait result
LOGD
(
"su: waiting child: [%d]
\n
"
,
child
);
int
status
,
code
;
if
(
waitpid
(
child
,
&
status
,
0
)
>
0
)
code
=
WEXITSTATUS
(
status
);
else
code
=
-
1
;
/* Passing the return code back to the client:
* The client might be closed unexpectedly (e.g. swipe a root app out of recents)
* In that case, writing to the client (which doesn't exist) will result in SIGPIPE
* Here we simply just ignore the situation.
*/
struct
sigaction
act
;
memset
(
&
act
,
0
,
sizeof
(
act
));
act
.
sa_handler
=
SIG_IGN
;
sigaction
(
SIGPIPE
,
&
act
,
NULL
);
LOGD
(
"su: return code: [%d]
\n
"
,
code
);
write
(
client
,
&
code
,
sizeof
(
code
));
close
(
client
);
// Restore default handler for SIGPIPE
act
.
sa_handler
=
SIG_DFL
;
sigaction
(
SIGPIPE
,
&
act
,
NULL
);
return
;
}
LOGD
(
"su: child process started
\n
"
);
// ack
// ack
write_int
(
client
,
0
);
write_int
(
client
,
0
);
...
@@ -285,9 +208,9 @@ void su_daemon_receiver(int client, struct ucred *credential) {
...
@@ -285,9 +208,9 @@ void su_daemon_receiver(int client, struct ucred *credential) {
// Migrate environment from client
// Migrate environment from client
char
path
[
32
],
buf
[
4096
];
char
path
[
32
],
buf
[
4096
];
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/cwd"
,
ctx
.
pid
);
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/cwd"
,
su_ctx
->
pid
);
xreadlink
(
path
,
ctx
.
cwd
,
sizeof
(
ctx
.
cwd
));
xreadlink
(
path
,
su_ctx
->
cwd
,
sizeof
(
su_ctx
->
cwd
));
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/environ"
,
ctx
.
pid
);
snprintf
(
path
,
sizeof
(
path
),
"/proc/%d/environ"
,
su_ctx
->
pid
);
memset
(
buf
,
0
,
sizeof
(
buf
));
memset
(
buf
,
0
,
sizeof
(
buf
));
int
fd
=
open
(
path
,
O_RDONLY
);
int
fd
=
open
(
path
,
O_RDONLY
);
read
(
fd
,
buf
,
sizeof
(
buf
));
read
(
fd
,
buf
,
sizeof
(
buf
));
...
@@ -319,7 +242,6 @@ void su_daemon_receiver(int client, struct ucred *credential) {
...
@@ -319,7 +242,6 @@ void su_daemon_receiver(int client, struct ucred *credential) {
// Get pts_slave
// Get pts_slave
char
*
pts_slave
=
read_string
(
client
);
char
*
pts_slave
=
read_string
(
client
);
LOGD
(
"su: pts_slave=[%s]
\n
"
,
pts_slave
);
// The FDs for each of the streams
// The FDs for each of the streams
int
infd
=
recv_fd
(
client
);
int
infd
=
recv_fd
(
client
);
...
@@ -331,13 +253,15 @@ void su_daemon_receiver(int client, struct ucred *credential) {
...
@@ -331,13 +253,15 @@ void su_daemon_receiver(int client, struct ucred *credential) {
close
(
client
);
close
(
client
);
if
(
pts_slave
[
0
])
{
if
(
pts_slave
[
0
])
{
LOGD
(
"su: pts_slave=[%s]
\n
"
,
pts_slave
);
// Check pts_slave file is owned by daemon_from_uid
// Check pts_slave file is owned by daemon_from_uid
struct
stat
st
;
struct
stat
st
;
xstat
(
pts_slave
,
&
st
);
xstat
(
pts_slave
,
&
st
);
// If caller is not root, ensure the owner of pts_slave is the caller
// If caller is not root, ensure the owner of pts_slave is the caller
if
(
st
.
st_uid
!=
credential
->
uid
&&
credential
->
uid
!=
0
)
{
if
(
st
.
st_uid
!=
su_ctx
->
info
->
uid
&&
su_ctx
->
info
->
uid
!=
0
)
{
LOGE
(
"su: Wrong permission of pts_slave"
);
LOGE
(
"su: Wrong permission of pts_slave"
);
su_ctx
->
info
->
access
.
policy
=
DENY
;
exit2
(
1
);
exit2
(
1
);
}
}
...
@@ -369,11 +293,92 @@ void su_daemon_receiver(int client, struct ucred *credential) {
...
@@ -369,11 +293,92 @@ void su_daemon_receiver(int client, struct ucred *credential) {
close
(
ptsfd
);
close
(
ptsfd
);
// Give main the reference
// Run the actual main
su_ctx
=
&
ctx
;
su_daemon_main
(
argc
,
argv
);
su_daemon_main
(
argc
,
argv
);
}
}
void
su_daemon_receiver
(
int
client
,
struct
ucred
*
credential
)
{
LOGD
(
"su: request from client: %d
\n
"
,
client
);
// Default values
struct
su_context
ctx
=
{
.
info
=
get_su_info
(
credential
->
uid
),
.
to
=
{
.
uid
=
UID_ROOT
,
.
login
=
0
,
.
keepenv
=
0
,
.
shell
=
DEFAULT_SHELL
,
.
command
=
NULL
,
},
.
pid
=
credential
->
pid
,
.
pipefd
=
{
-
1
,
-
1
}
};
// Fail fast
if
(
ctx
.
info
->
access
.
policy
==
DENY
&&
!
ctx
.
info
->
access
.
log
&&
!
ctx
.
info
->
access
.
notify
)
{
UNLOCK_UID
();
write_int
(
client
,
DENY
);
return
;
}
// If still not determined, open a pipe and wait for results
if
(
ctx
.
info
->
access
.
policy
==
QUERY
)
xpipe2
(
ctx
.
pipefd
,
O_CLOEXEC
);
/* Fork a new process, the child process will need to setsid,
* open a pseudo-terminal if needed, and will eventually run exec
* The parent process will wait for the result and
* send the return code back to our client
*/
int
child
=
xfork
();
if
(
child
==
0
)
{
su_ctx
=
&
ctx
;
su_executor
(
client
);
}
// Wait for results
if
(
ctx
.
pipefd
[
0
]
>=
0
)
{
xxread
(
ctx
.
pipefd
[
0
],
&
ctx
.
info
->
access
.
policy
,
sizeof
(
policy_t
));
close
(
ctx
.
pipefd
[
0
]);
close
(
ctx
.
pipefd
[
1
]);
}
// The policy is determined, unlock
UNLOCK_UID
();
// Info is now useless to us, decrement reference count
--
ctx
.
info
->
ref
;
// Wait result
LOGD
(
"su: waiting child: [%d]
\n
"
,
child
);
int
status
,
code
;
if
(
waitpid
(
child
,
&
status
,
0
)
>
0
)
code
=
WEXITSTATUS
(
status
);
else
code
=
-
1
;
/* Passing the return code back to the client:
* The client might be closed unexpectedly (e.g. swipe a root app out of recents)
* In that case, writing to the client (which doesn't exist) will result in SIGPIPE
* Here we simply just ignore the situation.
*/
struct
sigaction
act
;
memset
(
&
act
,
0
,
sizeof
(
act
));
act
.
sa_handler
=
SIG_IGN
;
sigaction
(
SIGPIPE
,
&
act
,
NULL
);
LOGD
(
"su: return code: [%d]
\n
"
,
code
);
write
(
client
,
&
code
,
sizeof
(
code
));
close
(
client
);
// Restore default handler for SIGPIPE
act
.
sa_handler
=
SIG_DFL
;
sigaction
(
SIGPIPE
,
&
act
,
NULL
);
return
;
}
/*
/*
* Connect daemon, send argc, argv, cwd, pts slave
* Connect daemon, send argc, argv, cwd, pts slave
*/
*/
...
...
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