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
9f1740cc
Commit
9f1740cc
authored
Mar 25, 2022
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add preliminary shared UID app support
parent
f2c15c77
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
332 additions
and
456 deletions
+332
-456
IRootUtils.aidl
...main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl
+8
-0
BaseDao.kt
...c/main/java/com/topjohnwu/magisk/core/magiskdb/BaseDao.kt
+0
-28
MagiskDB.kt
.../main/java/com/topjohnwu/magisk/core/magiskdb/MagiskDB.kt
+47
-0
PolicyDao.kt
...main/java/com/topjohnwu/magisk/core/magiskdb/PolicyDao.kt
+31
-44
Query.kt
...src/main/java/com/topjohnwu/magisk/core/magiskdb/Query.kt
+0
-161
SettingsDao.kt
...in/java/com/topjohnwu/magisk/core/magiskdb/SettingsDao.kt
+14
-16
StringDao.kt
...main/java/com/topjohnwu/magisk/core/magiskdb/StringDao.kt
+14
-16
SuLog.kt
...src/main/java/com/topjohnwu/magisk/core/model/su/SuLog.kt
+42
-3
SuPolicy.kt
.../main/java/com/topjohnwu/magisk/core/model/su/SuPolicy.kt
+37
-47
SuCallbackHandler.kt
...in/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt
+25
-37
SuRequestHandler.kt
...ain/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt
+7
-4
RootUtils.kt
...rc/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt
+36
-2
XAndroid.kt
app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt
+22
-51
PolicyRvItem.kt
...in/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt
+13
-19
SuperuserViewModel.kt
...a/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt
+7
-8
SuRequestActivity.kt
...va/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt
+10
-2
connect.cpp
native/jni/su/connect.cpp
+6
-4
su.hpp
native/jni/su/su.hpp
+1
-1
su_daemon.cpp
native/jni/su/su_daemon.cpp
+12
-13
No files found.
app/src/main/aidl/com/topjohnwu/magisk/core/utils/IRootUtils.aidl
0 → 100644
View file @
9f1740cc
//
IRootUtils
.
aidl
package
com
.
topjohnwu
.
magisk
.
core
.
utils
;
//
Declare
any
non
-
default
types
here
with
import
statements
interface
IRootUtils
{
android
.
app
.
ActivityManager
.
RunningAppProcessInfo
getAppProcess
(
int
pid
);
}
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/BaseDao.kt
deleted
100644 → 0
View file @
f2c15c77
package
com.topjohnwu.magisk.core.magiskdb
import
androidx.annotation.StringDef
abstract
class
BaseDao
{
object
Table
{
const
val
POLICY
=
"policies"
const
val
LOG
=
"logs"
const
val
SETTINGS
=
"settings"
const
val
STRINGS
=
"strings"
}
@StringDef
(
Table
.
POLICY
,
Table
.
LOG
,
Table
.
SETTINGS
,
Table
.
STRINGS
)
@Retention
(
AnnotationRetention
.
SOURCE
)
annotation
class
TableStrict
@TableStrict
abstract
val
table
:
String
inline
fun
<
reified
Builder
:
Query
.
Builder
>
buildQuery
(
builder
:
Builder
.()
->
Unit
=
{})
=
Builder
::
class
.
java
.
newInstance
()
.
apply
{
table
=
this
@BaseDao
.
table
}
.
apply
(
builder
)
.
toString
()
.
let
{
Query
(
it
)
}
}
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/MagiskDB.kt
0 → 100644
View file @
9f1740cc
package
com.topjohnwu.magisk.core.magiskdb
import
com.topjohnwu.magisk.ktx.await
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
open
class
MagiskDB
{
suspend
fun
<
R
>
exec
(
query
:
String
,
mapper
:
suspend
(
Map
<
String
,
String
>)
->
R
):
List
<
R
>
{
return
withContext
(
Dispatchers
.
IO
)
{
val
out
=
Shell
.
cmd
(
"magisk --sqlite '$query'"
).
await
().
out
out
.
map
{
line
->
line
.
split
(
"\\|"
.
toRegex
())
.
map
{
it
.
split
(
"="
,
limit
=
2
)
}
.
filter
{
it
.
size
==
2
}
.
associate
{
it
[
0
]
to
it
[
1
]
}
.
let
{
mapper
(
it
)
}
}
}
}
suspend
inline
fun
exec
(
query
:
String
)
{
exec
(
query
)
{}
}
fun
Map
<
String
,
Any
>.
toQuery
():
String
{
val
keys
=
this
.
keys
.
joinToString
(
","
)
val
values
=
this
.
values
.
joinToString
(
","
)
{
when
(
it
)
{
is
Boolean
->
if
(
it
)
"1"
else
"0"
is
Number
->
it
.
toString
()
else
->
"\"$it\""
}
}
return
"($keys) VALUES($values)"
}
object
Table
{
const
val
POLICY
=
"policies"
const
val
SETTINGS
=
"settings"
const
val
STRINGS
=
"strings"
}
}
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/PolicyDao.kt
View file @
9f1740cc
...
...
@@ -2,61 +2,48 @@ package com.topjohnwu.magisk.core.magiskdb
import
com.topjohnwu.magisk.core.Const
import
com.topjohnwu.magisk.core.model.su.SuPolicy
import
com.topjohnwu.magisk.core.model.su.
to
Policy
import
com.topjohnwu.magisk.core.model.su.
create
Policy
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.ktx.now
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.launch
import
timber.log.Timber
import
java.util.concurrent.TimeUnit
class
PolicyDao
:
MagiskDB
()
{
class
PolicyDao
:
BaseDao
()
{
override
val
table
:
String
=
Table
.
POLICY
suspend
fun
deleteOutdated
()
=
buildQuery
<
Delete
>
{
condition
{
greaterThan
(
"until"
,
"0"
)
and
{
lessThan
(
"until"
,
TimeUnit
.
MILLISECONDS
.
toSeconds
(
now
).
toString
())
}
or
{
lessThan
(
"until"
,
"0"
)
}
}
}.
commit
()
suspend
fun
deleteOutdated
()
{
val
nowSeconds
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
System
.
currentTimeMillis
())
val
query
=
"DELETE FROM ${Table.POLICY} WHERE "
+
"(until > 0 AND until < $nowSeconds) OR until < 0"
exec
(
query
)
}
suspend
fun
delete
(
uid
:
Int
)
=
buildQuery
<
Delete
>
{
condition
{
equals
(
"uid"
,
uid
)
}
}.
commit
()
suspend
fun
delete
(
uid
:
Int
)
{
val
query
=
"DELETE FROM ${Table.POLICY} WHERE uid == $uid"
exec
(
query
)
}
suspend
fun
fetch
(
uid
:
Int
)
=
buildQuery
<
Select
>
{
condition
{
equals
(
"uid"
,
uid
)
}
}.
query
().
first
().
toPolicyOrNull
()
suspend
fun
fetch
(
uid
:
Int
):
SuPolicy
?
{
val
query
=
"SELECT * FROM ${Table.POLICY} WHERE uid == $uid LIMIT = 1"
return
exec
(
query
)
{
it
.
toPolicyOrNull
()
}.
firstOrNull
()
}
suspend
fun
update
(
policy
:
SuPolicy
)
=
buildQuery
<
Replace
>
{
values
(
policy
.
toMap
())
}.
commit
()
suspend
fun
update
(
policy
:
SuPolicy
)
{
val
query
=
"REPLACE INTO ${Table.POLICY} ${policy.toMap().toQuery()}"
exec
(
query
)
}
suspend
fun
<
R
:
Any
>
fetchAll
(
mapper
:
(
SuPolicy
)
->
R
)
=
buildQuery
<
Select
>
{
condition
{
equals
(
"uid/100000"
,
Const
.
USER_ID
)
}
}.
query
{
it
.
toPolicyOrNull
()
?.
let
(
mapper
)
suspend
fun
fetchAll
():
List
<
SuPolicy
>
{
val
query
=
"SELECT * FROM ${Table.POLICY} WHERE uid/100000 == ${Const.USER_ID}"
return
exec
(
query
)
{
it
.
toPolicyOrNull
()
}.
filterNotNull
()
}
private
fun
Map
<
String
,
String
>.
toPolicyOrNull
():
SuPolicy
?
{
return
runCatching
{
toPolicy
(
AppContext
.
packageManager
)
}.
getOrElse
{
Timber
.
w
(
it
)
val
uid
=
getOrElse
(
"uid"
)
{
return
null
}
GlobalScope
.
launch
{
delete
(
uid
.
toInt
())
}
null
private
suspend
fun
Map
<
String
,
String
>.
toPolicyOrNull
():
SuPolicy
?
{
try
{
return
AppContext
.
packageManager
.
createPolicy
(
this
)
}
catch
(
e
:
Exception
)
{
Timber
.
w
(
e
)
val
uid
=
get
(
"uid"
)
?:
return
null
delete
(
uid
.
toInt
())
return
null
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/Query.kt
deleted
100644 → 0
View file @
f2c15c77
package
com.topjohnwu.magisk.core.magiskdb
import
androidx.annotation.StringDef
import
com.topjohnwu.magisk.ktx.await
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.async
import
kotlinx.coroutines.awaitAll
import
kotlinx.coroutines.withContext
class
Query
(
private
val
_query
:
String
)
{
val
query
get
()
=
"magisk --sqlite '$_query'"
interface
Builder
{
val
requestType
:
String
var
table
:
String
}
suspend
inline
fun
<
R
:
Any
>
query
(
crossinline
mapper
:
(
Map
<
String
,
String
>)
->
R
?):
List
<
R
>
=
withContext
(
Dispatchers
.
Default
)
{
Shell
.
cmd
(
query
).
await
().
out
.
map
{
line
->
async
{
line
.
split
(
"\\|"
.
toRegex
())
.
map
{
it
.
split
(
"="
,
limit
=
2
)
}
.
filter
{
it
.
size
==
2
}
.
map
{
it
[
0
]
to
it
[
1
]
}
.
toMap
()
.
let
(
mapper
)
}
}.
awaitAll
().
filterNotNull
()
}
suspend
inline
fun
query
()
=
query
{
it
}
suspend
inline
fun
commit
()
=
Shell
.
cmd
(
query
).
to
(
null
).
await
()
}
class
Delete
:
Query
.
Builder
{
override
val
requestType
:
String
=
"DELETE FROM"
override
var
table
=
""
private
var
condition
=
""
fun
condition
(
builder
:
Condition
.()
->
Unit
)
{
condition
=
Condition
().
apply
(
builder
).
toString
()
}
override
fun
toString
():
String
{
return
listOf
(
requestType
,
table
,
condition
).
joinToString
(
" "
)
}
}
class
Select
:
Query
.
Builder
{
override
val
requestType
:
String
get
()
=
"SELECT $fields FROM"
override
lateinit
var
table
:
String
private
var
fields
=
"*"
private
var
condition
=
""
private
var
orderField
=
""
fun
fields
(
vararg
newFields
:
String
)
{
if
(
newFields
.
isEmpty
())
{
fields
=
"*"
return
}
fields
=
newFields
.
joinToString
(
", "
)
}
fun
condition
(
builder
:
Condition
.()
->
Unit
)
{
condition
=
Condition
().
apply
(
builder
).
toString
()
}
fun
orderBy
(
field
:
String
,
@OrderStrict
order
:
String
)
{
orderField
=
"ORDER BY $field $order"
}
override
fun
toString
():
String
{
return
listOf
(
requestType
,
table
,
condition
,
orderField
).
joinToString
(
" "
)
}
}
class
Replace
:
Insert
()
{
override
val
requestType
:
String
=
"REPLACE INTO"
}
open
class
Insert
:
Query
.
Builder
{
override
val
requestType
:
String
=
"INSERT INTO"
override
lateinit
var
table
:
String
private
val
keys
get
()
=
_values
.
keys
.
joinToString
(
","
)
private
val
values
get
()
=
_values
.
values
.
joinToString
(
","
)
{
when
(
it
)
{
is
Boolean
->
if
(
it
)
"1"
else
"0"
is
Number
->
it
.
toString
()
else
->
"\"$it\""
}
}
private
var
_values
:
Map
<
String
,
Any
>
=
mapOf
()
fun
values
(
vararg
pairs
:
Pair
<
String
,
Any
>)
{
_values
=
pairs
.
toMap
()
}
fun
values
(
values
:
Map
<
String
,
Any
>)
{
_values
=
values
}
override
fun
toString
():
String
{
return
listOf
(
requestType
,
table
,
"($keys) VALUES($values)"
).
joinToString
(
" "
)
}
}
class
Condition
{
private
val
conditionWord
=
"WHERE %s"
private
var
condition
:
String
=
""
fun
equals
(
field
:
String
,
value
:
Any
)
{
condition
=
when
(
value
)
{
is
String
->
"$field=\"$value\""
else
->
"$field=$value"
}
}
fun
greaterThan
(
field
:
String
,
value
:
String
)
{
condition
=
"$field > $value"
}
fun
lessThan
(
field
:
String
,
value
:
String
)
{
condition
=
"$field < $value"
}
fun
greaterOrEqualTo
(
field
:
String
,
value
:
String
)
{
condition
=
"$field >= $value"
}
fun
lessOrEqualTo
(
field
:
String
,
value
:
String
)
{
condition
=
"$field <= $value"
}
fun
and
(
builder
:
Condition
.()
->
Unit
)
{
condition
=
"($condition AND ${Condition().apply(builder).condition})"
}
fun
or
(
builder
:
Condition
.()
->
Unit
)
{
condition
=
"($condition OR ${Condition().apply(builder).condition})"
}
override
fun
toString
():
String
{
return
conditionWord
.
format
(
condition
)
}
}
object
Order
{
const
val
ASC
=
"ASC"
const
val
DESC
=
"DESC"
}
@StringDef
(
Order
.
ASC
,
Order
.
DESC
)
@Retention
(
AnnotationRetention
.
SOURCE
)
annotation
class
OrderStrict
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/SettingsDao.kt
View file @
9f1740cc
package
com.topjohnwu.magisk.core.magiskdb
class
SettingsDao
:
BaseDao
()
{
class
SettingsDao
:
MagiskDB
()
{
override
val
table
=
Table
.
SETTINGS
suspend
fun
delete
(
key
:
String
)
{
val
query
=
"DELETE FROM ${Table.SETTINGS} WHERE key == \"$key\""
exec
(
query
)
}
suspend
fun
delete
(
key
:
String
)
=
buildQuery
<
Delete
>
{
condition
{
equals
(
"key"
,
key
)
}
}.
commit
()
suspend
fun
put
(
key
:
String
,
value
:
Int
)
=
buildQuery
<
Replace
>
{
values
(
"key"
to
key
,
"value"
to
value
)
}.
commit
()
suspend
fun
fetch
(
key
:
String
,
default
:
Int
=
-
1
)
=
buildQuery
<
Select
>
{
fields
(
"value"
)
condition
{
equals
(
"key"
,
key
)
}
}.
query
{
it
[
"value"
]
?.
toIntOrNull
()
}.
firstOrNull
()
?:
default
suspend
fun
put
(
key
:
String
,
value
:
Int
)
{
val
kv
=
mapOf
(
"key"
to
key
,
"value"
to
value
)
val
query
=
"REPLACE INTO ${Table.SETTINGS} ${kv.toQuery()}"
exec
(
query
)
}
suspend
fun
fetch
(
key
:
String
,
default
:
Int
=
-
1
):
Int
{
val
query
=
"SELECT value FROM ${Table.SETTINGS} WHERE key == \"$key\" LIMIT = 1"
return
exec
(
query
)
{
it
[
"value"
]
?.
toInt
()
}.
firstOrNull
()
?:
default
}
}
app/src/main/java/com/topjohnwu/magisk/core/magiskdb/StringDao.kt
View file @
9f1740cc
package
com.topjohnwu.magisk.core.magiskdb
class
StringDao
:
BaseDao
()
{
class
StringDao
:
MagiskDB
()
{
override
val
table
=
Table
.
STRINGS
suspend
fun
delete
(
key
:
String
)
{
val
query
=
"DELETE FROM ${Table.STRINGS} WHERE key == \"$key\""
exec
(
query
)
}
suspend
fun
delete
(
key
:
String
)
=
buildQuery
<
Delete
>
{
condition
{
equals
(
"key"
,
key
)
}
}.
commit
()
suspend
fun
put
(
key
:
String
,
value
:
String
)
=
buildQuery
<
Replace
>
{
values
(
"key"
to
key
,
"value"
to
value
)
}.
commit
()
suspend
fun
fetch
(
key
:
String
,
default
:
String
=
""
)
=
buildQuery
<
Select
>
{
fields
(
"value"
)
condition
{
equals
(
"key"
,
key
)
}
}.
query
{
it
[
"value"
]
}.
firstOrNull
()
?:
default
suspend
fun
put
(
key
:
String
,
value
:
String
)
{
val
kv
=
mapOf
(
"key"
to
key
,
"value"
to
value
)
val
query
=
"REPLACE INTO ${Table.STRINGS} ${kv.toQuery()}"
exec
(
query
)
}
suspend
fun
fetch
(
key
:
String
,
default
:
String
=
""
):
String
{
val
query
=
"SELECT value FROM ${Table.STRINGS} WHERE key == \"$key\" LIMIT = 1"
return
exec
(
query
)
{
it
[
"value"
]
}.
firstOrNull
()
?:
default
}
}
app/src/main/java/com/topjohnwu/magisk/core/model/su/SuLog.kt
View file @
9f1740cc
package
com.topjohnwu.magisk.core.model.su
import
android.content.pm.PackageInfo
import
android.content.pm.PackageManager
import
androidx.room.Entity
import
androidx.room.PrimaryKey
import
com.topjohnwu.magisk.ktx.
now
import
com.topjohnwu.magisk.ktx.
getLabel
@Entity
(
tableName
=
"logs"
)
data
class
SuLog
(
class
SuLog
(
val
fromUid
:
Int
,
val
toUid
:
Int
,
val
fromPid
:
Int
,
...
...
@@ -13,7 +15,44 @@ data class SuLog(
val
appName
:
String
,
val
command
:
String
,
val
action
:
Boolean
,
val
time
:
Long
=
now
val
time
:
Long
=
System
.
currentTimeMillis
()
)
{
@PrimaryKey
(
autoGenerate
=
true
)
var
id
:
Int
=
0
}
fun
PackageManager
.
createSuLog
(
info
:
PackageInfo
,
toUid
:
Int
,
fromPid
:
Int
,
command
:
String
,
policy
:
Int
):
SuLog
{
val
appInfo
=
info
.
applicationInfo
return
SuLog
(
fromUid
=
appInfo
.
uid
,
toUid
=
toUid
,
fromPid
=
fromPid
,
packageName
=
getNameForUid
(
appInfo
.
uid
)
!!
,
appName
=
appInfo
.
getLabel
(
this
),
command
=
command
,
action
=
policy
==
SuPolicy
.
ALLOW
)
}
fun
createSuLog
(
fromUid
:
Int
,
toUid
:
Int
,
fromPid
:
Int
,
command
:
String
,
policy
:
Int
):
SuLog
{
return
SuLog
(
fromUid
=
fromUid
,
toUid
=
toUid
,
fromPid
=
fromPid
,
packageName
=
"[UID] $fromUid"
,
appName
=
"[UID] $fromUid"
,
command
=
command
,
action
=
policy
==
SuPolicy
.
ALLOW
)
}
app/src/main/java/com/topjohnwu/magisk/core/model/su/SuPolicy.kt
View file @
9f1740cc
@file
:
SuppressLint
(
"InlinedApi"
)
package
com.topjohnwu.magisk.core.model.su
import
android.
annotation.SuppressLint
import
android.
content.pm.PackageInfo
import
android.content.pm.PackageManager
import
android.graphics.drawable.Drawable
import
com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.INTERACTIVE
import
com.topjohnwu.magisk.ktx.getLabel
import
com.topjohnwu.magisk.ktx.getPackageInfo
data
class
SuPolicy
(
class
SuPolicy
(
val
uid
:
Int
,
val
packageName
:
String
,
val
appName
:
String
,
val
icon
:
Drawable
,
var
policy
:
Int
=
INTERACTIVE
,
var
until
:
Long
=
-
1L
,
va
l
logging
:
Boolean
=
true
,
va
l
notification
:
Boolean
=
true
va
r
logging
:
Boolean
=
true
,
va
r
notification
:
Boolean
=
true
)
{
companion
object
{
...
...
@@ -25,10 +23,6 @@ data class SuPolicy(
const
val
ALLOW
=
2
}
fun
toLog
(
toUid
:
Int
,
fromPid
:
Int
,
command
:
String
)
=
SuLog
(
uid
,
toUid
,
fromPid
,
packageName
,
appName
,
command
,
policy
==
ALLOW
)
fun
toMap
()
=
mapOf
(
"uid"
to
uid
,
"package_name"
to
packageName
,
...
...
@@ -39,47 +33,43 @@ data class SuPolicy(
)
}
@Throws
(
PackageManager
.
NameNotFoundException
::
class
)
fun
Map
<
String
,
String
>.
toPolicy
(
pm
:
PackageManager
):
SuPolicy
{
val
uid
=
get
(
"uid"
)
?.
toIntOrNull
()
?:
-
1
val
packageName
=
get
(
"package_name"
).
orEmpty
()
val
info
=
pm
.
getApplicationInfo
(
packageName
,
PackageManager
.
MATCH_UNINSTALLED_PACKAGES
)
if
(
info
.
uid
!=
uid
)
throw
PackageManager
.
NameNotFoundException
()
fun
PackageManager
.
createPolicy
(
info
:
PackageInfo
):
SuPolicy
{
val
appInfo
=
info
.
applicationInfo
val
prefix
=
if
(
info
.
sharedUserId
==
null
)
""
else
"[SharedUID] "
return
SuPolicy
(
uid
=
uid
,
packageName
=
packageName
,
appName
=
info
.
getLabel
(
pm
),
icon
=
info
.
loadIcon
(
pm
),
policy
=
get
(
"policy"
)
?.
toIntOrNull
()
?:
INTERACTIVE
,
until
=
get
(
"until"
)
?.
toLongOrNull
()
?:
-
1L
,
logging
=
get
(
"logging"
)
?.
toIntOrNull
()
!=
0
,
notification
=
get
(
"notification"
)
?.
toIntOrNull
()
!=
0
uid
=
appInfo
.
uid
,
packageName
=
getNameForUid
(
appInfo
.
uid
)
!!
,
appName
=
"$prefix${appInfo.getLabel(this)}"
,
icon
=
appInfo
.
loadIcon
(
this
),
)
}
@Throws
(
PackageManager
.
NameNotFoundException
::
class
)
fun
Int
.
toPolicy
(
pm
:
PackageManager
,
policy
:
Int
=
INTERACTIVE
):
SuPolicy
{
val
pkg
=
pm
.
getPackagesForUid
(
this
)
?.
firstOrNull
()
?:
throw
PackageManager
.
NameNotFoundException
()
val
info
=
pm
.
getApplicationInfo
(
pkg
,
PackageManager
.
MATCH_UNINSTALLED_PACKAGES
)
return
SuPolicy
(
uid
=
info
.
uid
,
packageName
=
pkg
,
appName
=
info
.
getLabel
(
pm
),
icon
=
info
.
loadIcon
(
pm
),
policy
=
policy
)
fun
PackageManager
.
createPolicy
(
uid
:
Int
):
SuPolicy
{
val
info
=
getPackageInfo
(
uid
,
-
1
)
return
if
(
info
==
null
)
{
// We can assert getNameForUid does not return null because
// getPackageInfo will already throw if UID does not exist
val
name
=
getNameForUid
(
uid
)
!!
SuPolicy
(
uid
=
uid
,
packageName
=
name
,
appName
=
"[SharedUID] $name"
,
icon
=
defaultActivityIcon
,
)
}
else
{
createPolicy
(
info
)
}
}
fun
Int
.
toUidPolicy
(
pm
:
PackageManager
,
policy
:
Int
):
SuPolicy
{
return
SuPolicy
(
uid
=
this
,
packageName
=
"[UID] $this"
,
appName
=
"[UID] $this"
,
icon
=
pm
.
defaultActivityIcon
,
policy
=
policy
)
@Throws
(
PackageManager
.
NameNotFoundException
::
class
)
fun
PackageManager
.
createPolicy
(
map
:
Map
<
String
,
String
>):
SuPolicy
{
val
uid
=
map
[
"uid"
]
?.
toIntOrNull
()
?:
throw
IllegalArgumentException
()
val
policy
=
createPolicy
(
uid
)
map
[
"policy"
]
?.
toInt
()
?.
let
{
policy
.
policy
=
it
}
map
[
"until"
]
?.
toLong
()
?.
let
{
policy
.
until
=
it
}
map
[
"logging"
]
?.
toInt
()
?.
let
{
policy
.
logging
=
it
!=
0
}
map
[
"notification"
]
?.
toInt
()
?.
let
{
policy
.
notification
=
it
!=
0
}
return
policy
}
app/src/main/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt
View file @
9f1740cc
...
...
@@ -7,12 +7,12 @@ import com.topjohnwu.magisk.BuildConfig
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.core.Config
import
com.topjohnwu.magisk.core.model.su.SuPolicy
import
com.topjohnwu.magisk.core.model.su.toPolicy
import
com.topjohnwu.magisk.core.model.su.toUidPolicy
import
com.topjohnwu.magisk.core.model.su.createSuLog
import
com.topjohnwu.magisk.di.ServiceLocator
import
com.topjohnwu.magisk.ktx.getLabel
import
com.topjohnwu.magisk.ktx.getPackageInfo
import
com.topjohnwu.magisk.utils.Utils
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.runBlocking
import
timber.log.Timber
object
SuCallbackHandler
{
...
...
@@ -53,59 +53,47 @@ object SuCallbackHandler {
private
fun
handleLogging
(
context
:
Context
,
data
:
Bundle
)
{
val
fromUid
=
data
.
getIntComp
(
"from.uid"
,
-
1
)
val
notify
=
data
.
getBoolean
(
"notify"
,
true
)
val
allow
=
data
.
getIntComp
(
"policy"
,
SuPolicy
.
ALLOW
)
val
policy
=
data
.
getIntComp
(
"policy"
,
SuPolicy
.
ALLOW
)
val
toUid
=
data
.
getIntComp
(
"to.uid"
,
-
1
)
val
pid
=
data
.
getIntComp
(
"pid"
,
-
1
)
val
command
=
data
.
getString
(
"command"
,
""
)
val
pm
=
context
.
packageManager
val
policy
=
runCatching
{
fromUid
.
toPolicy
(
pm
,
allow
)
}.
getOrElse
{
GlobalScope
.
launch
{
ServiceLocator
.
policyDB
.
delete
(
fromUid
)
}
fromUid
.
toUidPolicy
(
pm
,
allow
)
}
val
log
=
runCatching
{
pm
.
getPackageInfo
(
fromUid
,
pid
)
?.
let
{
pm
.
createSuLog
(
it
,
toUid
,
pid
,
command
,
policy
)
}
}.
getOrNull
()
?:
createSuLog
(
fromUid
,
toUid
,
pid
,
command
,
policy
)
if
(
notify
)
notify
(
context
,
policy
)
notify
(
context
,
log
.
action
,
log
.
appName
)
val
toUid
=
data
.
getIntComp
(
"to.uid"
,
-
1
)
val
pid
=
data
.
getIntComp
(
"pid"
,
-
1
)
val
command
=
data
.
getString
(
"command"
,
""
)
val
log
=
policy
.
toLog
(
toUid
=
toUid
,
fromPid
=
pid
,
command
=
command
)
GlobalScope
.
launch
{
ServiceLocator
.
logRepo
.
insert
(
log
)
}
runBlocking
{
ServiceLocator
.
logRepo
.
insert
(
log
)
}
}
private
fun
handleNotify
(
context
:
Context
,
data
:
Bundle
)
{
val
fromUid
=
data
.
getIntComp
(
"from.uid"
,
-
1
)
val
allow
=
data
.
getIntComp
(
"policy"
,
SuPolicy
.
ALLOW
)
val
uid
=
data
.
getIntComp
(
"from.uid"
,
-
1
)
val
pid
=
data
.
getIntComp
(
"pid"
,
-
1
)
val
policy
=
data
.
getIntComp
(
"policy"
,
SuPolicy
.
ALLOW
)
val
pm
=
context
.
packageManager
val
appName
=
runCatching
{
pm
.
getPackageInfo
(
uid
,
pid
)
?.
applicationInfo
?.
getLabel
(
pm
)
}.
getOrNull
()
?:
"[UID] $uid"
val
policy
=
runCatching
{
fromUid
.
toPolicy
(
pm
,
allow
)
}.
getOrElse
{
GlobalScope
.
launch
{
ServiceLocator
.
policyDB
.
delete
(
fromUid
)
}
fromUid
.
toUidPolicy
(
pm
,
allow
)
}
notify
(
context
,
policy
)
notify
(
context
,
policy
==
SuPolicy
.
ALLOW
,
appName
)
}
private
fun
notify
(
context
:
Context
,
policy
:
SuPolicy
)
{
private
fun
notify
(
context
:
Context
,
granted
:
Boolean
,
appName
:
String
)
{
if
(
Config
.
suNotification
==
Config
.
Value
.
NOTIFICATION_TOAST
)
{
val
resId
=
if
(
policy
.
policy
==
SuPolicy
.
ALLOW
)
val
resId
=
if
(
granted
)
R
.
string
.
su_allow_toast
else
R
.
string
.
su_deny_toast
Utils
.
toast
(
context
.
getString
(
resId
,
policy
.
appName
),
Toast
.
LENGTH_SHORT
)
Utils
.
toast
(
context
.
getString
(
resId
,
appName
),
Toast
.
LENGTH_SHORT
)
}
}
}
app/src/main/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt
View file @
9f1740cc
...
...
@@ -6,7 +6,8 @@ import com.topjohnwu.magisk.BuildConfig
import
com.topjohnwu.magisk.core.Config
import
com.topjohnwu.magisk.core.magiskdb.PolicyDao
import
com.topjohnwu.magisk.core.model.su.SuPolicy
import
com.topjohnwu.magisk.core.model.su.toPolicy
import
com.topjohnwu.magisk.core.model.su.createPolicy
import
com.topjohnwu.magisk.ktx.getPackageInfo
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
...
...
@@ -60,10 +61,12 @@ class SuRequestHandler(
private
suspend
fun
init
(
intent
:
Intent
)
=
withContext
(
Dispatchers
.
IO
)
{
try
{
val
name
=
intent
.
getStringExtra
(
"fifo"
)
?:
throw
SuRequestError
()
val
fifo
=
intent
.
getStringExtra
(
"fifo"
)
?:
throw
SuRequestError
()
val
uid
=
intent
.
getIntExtra
(
"uid"
,
-
1
).
also
{
if
(
it
<
0
)
throw
SuRequestError
()
}
output
=
DataOutputStream
(
FileOutputStream
(
name
).
buffered
())
policy
=
uid
.
toPolicy
(
pm
)
val
pid
=
intent
.
getIntExtra
(
"pid"
,
-
1
)
val
info
=
pm
.
getPackageInfo
(
uid
,
pid
)
?:
throw
SuRequestError
()
output
=
DataOutputStream
(
FileOutputStream
(
fifo
).
buffered
())
policy
=
pm
.
createPolicy
(
info
)
true
}
catch
(
e
:
Exception
)
{
when
(
e
)
{
...
...
app/src/main/java/com/topjohnwu/magisk/core/utils/RootUtils.kt
View file @
9f1740cc
package
com.topjohnwu.magisk.core.utils
import
android.app.ActivityManager
import
android.content.ComponentName
import
android.content.Intent
import
android.content.ServiceConnection
import
android.os.Binder
import
android.os.IBinder
import
androidx.core.content.getSystemService
import
com.topjohnwu.superuser.Shell
import
com.topjohnwu.superuser.ShellUtils
import
com.topjohnwu.superuser.ipc.RootService
import
timber.log.Timber
import
java.io.File
import
java.util.concurrent.locks.AbstractQueuedSynchronizer
class
RootUtils
(
stub
:
Any
?)
:
RootService
()
{
private
val
className
:
String
=
stub
?.
javaClass
?.
name
?:
javaClass
.
name
private
lateinit
var
am
:
ActivityManager
constructor
()
:
this
(
null
)
{
Timber
.
plant
(
Timber
.
DebugTree
())
}
override
fun
onCreate
()
{
am
=
getSystemService
()
!!
}
override
fun
getComponentName
():
ComponentName
{
return
ComponentName
(
packageName
,
className
)
}
override
fun
onBind
(
intent
:
Intent
):
IBinder
{
return
Binder
()
return
object
:
IRootUtils
.
Stub
()
{
override
fun
getAppProcess
(
pid
:
Int
)
=
safe
(
null
)
{
getAppProcessImpl
(
pid
)
}
}
}
private
inline
fun
<
T
>
safe
(
default
:
T
,
block
:
()
->
T
):
T
{
return
try
{
block
()
}
catch
(
e
:
Throwable
)
{
Timber
.
e
(
e
)
default
}
}
private
fun
getAppProcessImpl
(
_pid
:
Int
):
ActivityManager
.
RunningAppProcessInfo
?
{
val
procList
=
am
.
runningAppProcesses
var
pid
=
_pid
while
(
pid
>
1
)
{
val
proc
=
procList
.
find
{
it
.
pid
==
pid
}
if
(
proc
!=
null
)
return
proc
// Find PPID
File
(
"/proc/$pid/status"
).
useLines
{
val
s
=
it
.
find
{
line
->
line
.
startsWith
(
"PPid:"
)
}
pid
=
s
?.
substring
(
5
)
?.
trim
()
?.
toInt
()
?:
-
1
}
}
return
null
}
object
Connection
:
AbstractQueuedSynchronizer
(),
ServiceConnection
{
...
...
app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt
View file @
9f1740cc
...
...
@@ -7,10 +7,10 @@ import android.content.Context
import
android.content.ContextWrapper
import
android.content.Intent
import
android.content.pm.ApplicationInfo
import
android.content.pm.PackageInfo
import
android.content.pm.PackageManager
import
android.content.pm.PackageManager.
*
import
android.content.pm.PackageManager.
PERMISSION_GRANTED
import
android.content.res.Configuration
import
android.content.res.Resources
import
android.database.Cursor
import
android.graphics.Bitmap
import
android.graphics.Canvas
...
...
@@ -19,40 +19,26 @@ import android.graphics.drawable.BitmapDrawable
import
android.graphics.drawable.LayerDrawable
import
android.net.Uri
import
android.os.Build.VERSION.SDK_INT
import
android.text.PrecomputedText
import
android.view.View
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.view.inputmethod.InputMethodManager
import
android.widget.TextView
import
androidx.annotation.ColorRes
import
androidx.annotation.DrawableRes
import
androidx.appcompat.content.res.AppCompatResources
import
androidx.core.content.ContextCompat
import
androidx.core.content.getSystemService
import
androidx.core.net.toUri
import
androidx.core.text.PrecomputedTextCompat
import
androidx.core.view.isGone
import
androidx.core.widget.TextViewCompat
import
androidx.databinding.BindingAdapter
import
androidx.fragment.app.Fragment
import
androidx.interpolator.view.animation.FastOutSlowInInterpolator
import
androidx.lifecycle.lifecycleScope
import
androidx.transition.AutoTransition
import
androidx.transition.TransitionManager
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.core.Const
import
com.topjohnwu.magisk.core.
base.BaseActivity
import
com.topjohnwu.magisk.core.
utils.RootUtils
import
com.topjohnwu.magisk.core.utils.currentLocale
import
com.topjohnwu.magisk.di.AppContext
import
com.topjohnwu.magisk.utils.DynamicClassLoader
import
com.topjohnwu.magisk.utils.Utils
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.launch
import
java.io.File
import
kotlin.Array
import
kotlin.String
import
java.lang.reflect.Array
as
JArray
fun
Context
.
rawResource
(
id
:
Int
)
=
resources
.
openRawResource
(
id
)
...
...
@@ -79,8 +65,6 @@ val Context.deviceProtectedContext: Context get() =
createDeviceProtectedStorageContext
()
}
else
{
this
}
fun
Intent
.
startActivity
(
context
:
Context
)
=
context
.
startActivity
(
this
)
fun
Intent
.
startActivityWithRoot
()
{
val
args
=
mutableListOf
(
"am"
,
"start"
,
"--user"
,
Const
.
USER_ID
.
toString
())
val
cmd
=
toCommand
(
args
).
joinToString
(
" "
)
...
...
@@ -185,8 +169,6 @@ fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<S
return
args
}
fun
Intent
.
chooser
(
title
:
String
=
"Pick an app"
)
=
Intent
.
createChooser
(
this
,
title
)
fun
Context
.
cachedFile
(
name
:
String
)
=
File
(
cacheDir
,
name
)
fun
<
Result
>
Cursor
.
toList
(
transformer
:
(
Cursor
)
->
Result
):
List
<
Result
>
{
...
...
@@ -209,34 +191,6 @@ fun ApplicationInfo.getLabel(pm: PackageManager): String {
return
loadLabel
(
pm
).
toString
()
}
fun
Intent
.
exists
(
packageManager
:
PackageManager
)
=
resolveActivity
(
packageManager
)
!=
null
fun
Context
.
colorCompat
(
@ColorRes
id
:
Int
)
=
try
{
ContextCompat
.
getColor
(
this
,
id
)
}
catch
(
e
:
Resources
.
NotFoundException
)
{
null
}
fun
Context
.
colorStateListCompat
(
@ColorRes
id
:
Int
)
=
try
{
ContextCompat
.
getColorStateList
(
this
,
id
)
}
catch
(
e
:
Resources
.
NotFoundException
)
{
null
}
fun
Context
.
drawableCompat
(
@DrawableRes
id
:
Int
)
=
AppCompatResources
.
getDrawable
(
this
,
id
)
/**
* Pass [start] and [end] dimensions, function will return left and right
* with respect to RTL layout direction
*/
fun
Context
.
startEndToLeftRight
(
start
:
Int
,
end
:
Int
):
Pair
<
Int
,
Int
>
{
if
(
resources
.
configuration
.
layoutDirection
==
View
.
LAYOUT_DIRECTION_RTL
)
{
return
end
to
start
}
return
start
to
end
}
fun
Context
.
openUrl
(
url
:
String
)
=
Utils
.
openLink
(
this
,
url
.
toUri
())
inline
fun
<
reified
T
>
T
.
createClassLoader
(
apk
:
File
)
=
DynamicClassLoader
(
apk
,
T
::
class
.
java
.
classLoader
)
...
...
@@ -308,3 +262,20 @@ fun getProperty(key: String, def: String): String {
}
return
def
}
@SuppressLint
(
"InlinedApi"
)
@Throws
(
PackageManager
.
NameNotFoundException
::
class
)
fun
PackageManager
.
getPackageInfo
(
uid
:
Int
,
pid
:
Int
):
PackageInfo
?
{
val
flag
=
PackageManager
.
MATCH_UNINSTALLED_PACKAGES
val
pkgs
=
getPackagesForUid
(
uid
)
?:
throw
PackageManager
.
NameNotFoundException
()
return
if
(
pkgs
.
size
>
1
)
{
if
(
pid
<=
0
)
return
null
// Try to find package name from PID
val
proc
=
RootUtils
.
obj
?.
getAppProcess
(
pid
)
?:
return
null
val
pkg
=
proc
.
pkgList
[
0
]
getPackageInfo
(
pkg
,
flag
)
}
else
{
getPackageInfo
(
pkgs
[
0
],
flag
)
}
}
app/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt
View file @
9f1740cc
...
...
@@ -20,35 +20,29 @@ class PolicyRvItem(
var
isExpanded
=
false
set
(
value
)
=
set
(
value
,
field
,
{
field
=
it
},
BR
.
expanded
)
// This property hosts the policy state
var
policyState
=
item
.
policy
==
SuPolicy
.
ALLOW
set
(
value
)
=
set
(
value
,
field
,
{
field
=
it
},
BR
.
enabled
)
// This property binds with the UI state
@get
:
Bindable
var
isEnabled
get
()
=
policyState
set
(
value
)
=
set
(
value
,
policyState
,
{
viewModel
.
togglePolicy
(
this
,
it
)
},
BR
.
enabled
)
get
()
=
item
.
policy
==
SuPolicy
.
ALLOW
set
(
value
)
{
if
(
value
!=
isEnabled
)
viewModel
.
togglePolicy
(
this
,
value
)
}
@get
:
Bindable
var
shouldNotify
=
item
.
notification
set
(
value
)
=
set
(
value
,
field
,
{
field
=
it
},
BR
.
shouldNotify
)
{
viewModel
.
updatePolicy
(
updatedPolicy
,
isLogging
=
false
)
var
shouldNotify
get
()
=
item
.
notification
set
(
value
)
=
set
(
value
,
shouldNotify
,
{
item
.
notification
=
it
},
BR
.
shouldNotify
)
{
viewModel
.
updatePolicy
(
item
,
isLogging
=
false
)
}
@get
:
Bindable
var
shouldLog
=
item
.
logging
set
(
value
)
=
set
(
value
,
field
,
{
field
=
it
},
BR
.
shouldLog
)
{
viewModel
.
updatePolicy
(
updatedPolicy
,
isLogging
=
true
)
var
shouldLog
get
()
=
item
.
logging
set
(
value
)
=
set
(
value
,
shouldLog
,
{
item
.
logging
=
it
},
BR
.
shouldLog
)
{
viewModel
.
updatePolicy
(
item
,
isLogging
=
true
)
}
private
val
updatedPolicy
get
()
=
item
.
copy
(
policy
=
if
(
policyState
)
SuPolicy
.
ALLOW
else
SuPolicy
.
DENY
,
notification
=
shouldNotify
,
logging
=
shouldLog
)
fun
toggleExpand
()
{
isExpanded
=
!
isExpanded
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt
View file @
9f1740cc
...
...
@@ -47,12 +47,12 @@ class SuperuserViewModel(
return
@launch
}
state
=
State
.
LOADING
val
(
policies
,
diff
)
=
withContext
(
Dispatchers
.
Default
)
{
val
(
policies
,
diff
)
=
withContext
(
Dispatchers
.
IO
)
{
db
.
deleteOutdated
()
val
policies
=
db
.
fetchAll
{
val
policies
=
db
.
fetchAll
().
map
{
PolicyRvItem
(
it
,
it
.
icon
,
this
@SuperuserViewModel
)
}.
sortedWith
(
compareBy
(
{
it
.
item
.
appName
.
toLowerC
ase
(
currentLocale
)
},
{
it
.
item
.
appName
.
lowerc
ase
(
currentLocale
)
},
{
it
.
item
.
packageName
}
))
policies
to
itemsPolicies
.
calculateDiff
(
policies
)
...
...
@@ -107,14 +107,13 @@ class SuperuserViewModel(
fun
togglePolicy
(
item
:
PolicyRvItem
,
enable
:
Boolean
)
{
fun
updateState
()
{
item
.
policyState
=
enable
val
policy
=
if
(
enable
)
SuPolicy
.
ALLOW
else
SuPolicy
.
DENY
val
app
=
item
.
item
.
copy
(
policy
=
policy
)
item
.
item
.
policy
=
policy
item
.
notifyPropertyChanged
(
BR
.
enabled
)
viewModelScope
.
launch
{
db
.
update
(
app
)
val
res
=
if
(
app
.
policy
==
SuPolicy
.
ALLOW
)
R
.
string
.
su_snack_grant
db
.
update
(
item
.
item
)
val
res
=
if
(
item
.
item
.
policy
==
SuPolicy
.
ALLOW
)
R
.
string
.
su_snack_grant
else
R
.
string
.
su_snack_deny
SnackbarEvent
(
res
.
asText
(
item
.
item
.
appName
)).
publish
()
}
...
...
app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt
View file @
9f1740cc
...
...
@@ -7,6 +7,7 @@ import android.os.Build
import
android.os.Bundle
import
android.view.Window
import
android.view.WindowManager
import
androidx.lifecycle.lifecycleScope
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.arch.UIActivity
import
com.topjohnwu.magisk.core.su.SuCallbackHandler
...
...
@@ -14,6 +15,9 @@ import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
import
com.topjohnwu.magisk.databinding.ActivityRequestBinding
import
com.topjohnwu.magisk.di.viewModel
import
com.topjohnwu.magisk.ui.theme.Theme
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.withContext
open
class
SuRequestActivity
:
UIActivity
<
ActivityRequestBinding
>()
{
...
...
@@ -40,8 +44,12 @@ open class SuRequestActivity : UIActivity<ActivityRequestBinding>() {
if
(
action
==
REQUEST
)
{
viewModel
.
handleRequest
(
intent
)
}
else
{
SuCallbackHandler
.
run
(
this
,
action
,
intent
.
extras
)
finish
()
lifecycleScope
.
launch
{
withContext
(
Dispatchers
.
IO
)
{
SuCallbackHandler
.
run
(
this
@SuRequestActivity
,
action
,
intent
.
extras
)
}
finish
()
}
}
}
else
{
finish
()
...
...
native/jni/su/connect.cpp
View file @
9f1740cc
...
...
@@ -191,6 +191,7 @@ void app_notify(const su_context &ctx) {
vector
<
Extra
>
extras
;
extras
.
reserve
(
2
);
extras
.
emplace_back
(
"from.uid"
,
ctx
.
info
->
uid
);
extras
.
emplace_back
(
"pid"
,
ctx
.
pid
);
extras
.
emplace_back
(
"policy"
,
ctx
.
info
->
access
.
policy
);
exec_cmd
(
"notify"
,
extras
,
ctx
.
info
);
...
...
@@ -198,21 +199,22 @@ void app_notify(const su_context &ctx) {
}
}
int
app_request
(
const
s
hared_ptr
<
su_info
>
&
info
)
{
int
app_request
(
const
s
u_context
&
ctx
)
{
// Create FIFO
char
fifo
[
64
];
strcpy
(
fifo
,
"/dev/socket/"
);
gen_rand_str
(
fifo
+
12
,
32
,
true
);
mkfifo
(
fifo
,
0600
);
chown
(
fifo
,
info
->
mgr_st
.
st_uid
,
info
->
mgr_st
.
st_gid
);
chown
(
fifo
,
ctx
.
info
->
mgr_st
.
st_uid
,
ctx
.
info
->
mgr_st
.
st_gid
);
setfilecon
(
fifo
,
"u:object_r:"
SEPOL_FILE_TYPE
":s0"
);
// Send request
vector
<
Extra
>
extras
;
extras
.
reserve
(
2
);
extras
.
emplace_back
(
"fifo"
,
fifo
);
extras
.
emplace_back
(
"uid"
,
info
->
eval_uid
);
exec_cmd
(
"request"
,
extras
,
info
,
false
);
extras
.
emplace_back
(
"uid"
,
ctx
.
info
->
eval_uid
);
extras
.
emplace_back
(
"pid"
,
ctx
.
pid
);
exec_cmd
(
"request"
,
extras
,
ctx
.
info
,
false
);
// Wait for data input for at most 70 seconds
int
fd
=
xopen
(
fifo
,
O_RDONLY
|
O_CLOEXEC
|
O_NONBLOCK
);
...
...
native/jni/su/su.hpp
View file @
9f1740cc
...
...
@@ -60,4 +60,4 @@ struct su_context {
void
app_log
(
const
su_context
&
ctx
);
void
app_notify
(
const
su_context
&
ctx
);
int
app_request
(
const
s
td
::
shared_ptr
<
su_info
>
&
info
);
int
app_request
(
const
s
u_context
&
ctx
);
native/jni/su/su_daemon.cpp
View file @
9f1740cc
...
...
@@ -193,20 +193,7 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
info
->
access
=
NO_SU_ACCESS
;
return
info
;
}
}
else
{
return
info
;
}
// If still not determined, ask manager
int
fd
=
app_request
(
info
);
if
(
fd
<
0
)
{
info
->
access
.
policy
=
DENY
;
}
else
{
int
ret
=
read_int_be
(
fd
);
info
->
access
.
policy
=
ret
<
0
?
DENY
:
static_cast
<
policy_t
>
(
ret
);
close
(
fd
);
}
return
info
;
}
...
...
@@ -237,6 +224,18 @@ void su_daemon_handler(int client, const sock_cred *cred) {
read_string
(
client
,
ctx
.
req
.
shell
);
read_string
(
client
,
ctx
.
req
.
command
);
// If still not determined, ask manager
if
(
ctx
.
info
->
access
.
policy
==
QUERY
)
{
int
fd
=
app_request
(
ctx
);
if
(
fd
<
0
)
{
ctx
.
info
->
access
.
policy
=
DENY
;
}
else
{
int
ret
=
read_int_be
(
fd
);
ctx
.
info
->
access
.
policy
=
ret
<
0
?
DENY
:
static_cast
<
policy_t
>
(
ret
);
close
(
fd
);
}
}
if
(
ctx
.
info
->
access
.
log
)
app_log
(
ctx
);
else
if
(
ctx
.
info
->
access
.
notify
)
...
...
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