Open CyanChanges opened 1 year ago
well, when kernelSU appeared on the scene, we changed the logic to
if pref useMountMaster
is set and the shell has --mount-master (according to libsu):
use echo "some command" | su --mount-master
else if pref useSu0 is set:
use echo "some command" | su 0
(so running as uid 0)
else:
use echo "some command" | su
I now use kernelSU myself (but without special settings).
I see it has --mount-master, so su 0 shouldn't be used. However we rely on libsu from the Magisk author. So, it seems it uses su 0 internally (and as far as I know, that's the way all superuser solutions worked before kernelSU).
Just curious, why do you need the uid different from 0?
that said, I think I have a fairly current kernelSU implementation. But you may have another version (even a newer one).
Maybe yours doesn't provide the --mount-master
option or it's disabled in some way.
I would say "please try if disabling useMountMaster
and useSu0
changes the behavior".
But you are not getting far enough to do that...
You could edit the xml file in shared_prefs folder inside NBs data folder.
Maybe we should disable both options by default.
We already use nsenter if available, so --mount-master
shouldn't be necessary and su
should default to the appropriate uid.
if pref
useMountMaster
is set and the shell has --mount-master (according to libsu): useecho "some command" | su --mount-master
else if pref useSu0 is set: useecho "some command" | su 0
(so running as uid 0) else: useecho "some command" | su
as I said, we changed the code at that time...
But currently it's only using su --mount-master
or su
.
The two preferences don't exist any more.
if mount-master exists is checked by this command:
echo true | su --mount-master 0
The 0
should probably be removed.
But I think, it never gets to that one, because the root check already fails and that's done by libsu.
the latest libsu code uses this:
public synchronized static Boolean isAppGrantedRoot() {
if (currentRootState < 0) {
if (Process.myUid() == 0) {
// The current process is a root service
currentRootState = 2;
return true;
}
// noinspection ConstantConditions
for (String path : System.getenv("PATH").split(":")) {
File su = new File(path, "su");
if (su.canExecute()) {
// We don't actually know whether the app has been granted root access.
// Do NOT set the value as a confirmed state.
currentRootState = 1;
return null;
}
}
currentRootState = 0;
return false;
}
switch (currentRootState) {
case 0 : return false;
case 2 : return true;
default: return null;
}
}
so, it first looks if it is running as uid 0, which return true,
then it tries to find an executable su
,
no su -> returns false
otherwise the result is null
well, at least I didn't expect this, we simply return the result...which should create an exception, that is probably catched somewhere.
I now have kernelSu myself...
i wonder how this works:
Configure App Profile with uid != 0 like 100
there are several aspects... e.g.
it obviously cannot work if the uid doesn't have enough permissions for NB. Did you already investigate that whole topic? I don't have time and motivation to add another topic to my big list.
Also, why do you want to change the uid at all? NB was created with full control in mind, nobody ever thought about granular permission control like KSU can do.
When I got KSU, I tried to grant granular permissions, and at the end I had granted all of them. I'm sure this could be reduced, but it's not easy to find out.
well, when kernelSU appeared on the scene, we changed the logic to
if pref
useMountMaster
is set and the shell has --mount-master (according to libsu): useecho "some command" | su --mount-master
else if pref useSu0 is set: useecho "some command" | su 0
(so running as uid 0) else: useecho "some command" | su
I now use kernelSU myself (but without special settings).
I see it has --mount-master, so su 0 shouldn't be used. However we rely on libsu from the Magisk author. So, it seems it uses su 0 internally (and as far as I know, that's the way all superuser solutions worked before kernelSU).
Just curious, why do you need the uid different from 0?
If uid is zero, you can simply use su
again to grant non-limited full root permission. i want minimal permission granted. This is why I configured this Profile.
In the mainland of China, many apps abuse and their permissions. Probably it isn't happening here. But nobody know when root app have dangerous code can brick my device or something else.
For root apps full root may be dangerous and it's too much. But no strong force to supervise and securing the app about what did they done to my device.
I now have kernelSu myself...
i wonder how this works:
Configure App Profile with uid != 0 like 100
there are several aspects... e.g.
- can you use any uid?
- should it exist before?
- is it reused if it exists?
- is it created by KSU if it doesn't exist?
- are the permissions taken from an existing uid?
- are they changed by KSU?
- what about the selinux context (can also be configured in KSU)?
it obviously cannot work if the uid doesn't have enough permissions for NB. Did you already investigate that whole topic? I don't have time and motivation to add another topic to my big list.
Also, why do you want to change the uid at all? NB was created with full control in mind, nobody ever thought about granular permission control like KSU can do.
When I got KSU, I tried to grant granular permissions, and at the end I had granted all of them. I'm sure this could be reduced, but it's not easy to find out.
App can just pass the check if su is able to use. You don't want to tweak the options. It's okay. It is surely complex to figure out what these all options going to do. Just let the others which want to do it can tweak them.
You can just keep this issue. When you get free time, change a few lines to make uid!=0 pass the check.
well, not using su 0
but something else (not sure what?) is the first step.
After you pass the check, you probably want that it works, right?
I asked those questions for two reasons:
I want to test it on a device and need to configure it the same like you do
I want to understand how NB must proceed when uid!=0
It's a bit difficult with that su
command.
As far as I know the kernelSU developer has somehow redefined it's nature.
Normally su
changes the uid to someone else, so su $uid ...
changes to that uid and executes the given command, or it swithces to that uid if no command given.
KernelSU redefines it as su==sh
.
With standard su su 0
is the same as su
, because 0 is the default uid.
With a standard su, if not using 0, you would need to know the other uid and use that explicitely. E.g. if uid is set to 100 , you need to execute commands with su 100
, to run the commands on that uid.
If you would use su
, it would run the command as uid=0 instead, so not what you want.
What's the behavior of kernelSU su command without the uid parameter? Does it default to the configured uid?
I tried to test this:
I am debugging now...
as profile I use adb, which is uid/gid=2000, no capabilities (not sure which are needed)
before any checking takes place, libsu creates a shell first and this fails with:
java.io.IOException: Cannot run program "su": error=13, Permission denied
If I assign adb profile to Shell (com.android.shell) it behaves the same. It cannot execute su. Not sure why that adb profile exists. It's not something I would want for an adb shell.
If I use a custom kernelSU profile, based on adb but with all capabilities added, libsu still cannot create a shell.
So for now it's not NB's fault. If libsu cannot create a privileged shell there is no chance to proceed.
Currently, I don't understand, why libsu cannot create a shell...
btw. you see this in the log:
libsu shell status = _status_ = UNKNOWN|NON_ROOT_SHELL|ROOT_SHELL|ROOT_MOUNT_MASTER|unknown code
(note: you need to enable logToSystemLogcat before switching the profile, otherwise you want get a log, something on my list)
I get 0 = NON_ROOT_SHELL
, because libsu cannot create a privileged shell.
Do other apps using libsu work with your non-0 configuration?
can you show the lower part of your configuration?
libsu is explicitly programmed to check uid=0, otherwise it is not seen as a root shell:
private Integer shellCheck() throws IOException {
...
this.STDIN.write("id\n".getBytes(StandardCharsets.UTF_8));
this.STDIN.flush();
s = br.readLine();
if (!TextUtils.isEmpty(s) && s.contains("uid=0")) {
status = 1;
Utils.setConfirmedRootState(true);
...
for me it works with this profile:
the key is uid=0, apart from that, you can restrict a lot, but have to make sure NB's actions still work: E.g. I think removing capabilities for audition, oder network related etc. shoudn't be a problem.
Not sure what is different, when you use another uid, in most cases being part of the root group (like in your profile) should have similar effects. Usually permission management is done via groups.
Note, NB cannot be aware of all the possible combinations. If you use such a profile, you are on your own. If you want to report an issue, you should first reproduce it with the default profile. I guess, concrete suggestions (should be PRs) might be accepted.
NB does very minimal checks, the status of libsu is more or less the only condition and this is depending on uid=0. NB itself does no more enforce uid=0. If root works with another user, libsu should be changed.
we could theoretically replace the libsu check by checkiing other things like access to /data and maybe some commands we use like pm.
However, as far as I understand the code, libsu throws away the shell if it is not root = uid 0:
if (shell == null && !this.hasFlags(1)) {
try {
shell = this.build("su");
if (!shell.isRoot()) {
shell = null;
}
} catch (NoShellException var3) {
}
}
and then creates a user shell instead:
if (shell == null) {
if (!this.hasFlags(1)) {
Utils.setConfirmedRootState(false);
}
shell = this.build("sh");
}
which should mean, it will not work with root commands later.
Though, I'm not sure how that kernelSU profile concept works. Would it also assign the given capabilities to non su commands? Does the whole app have the given rights without using su?
well, not using
su 0
but something else (not sure what?) is the first step. After you pass the check, you probably want that it works, right?I asked those questions for two reasons:
- I want to test it on a device and need to configure it the same like you do
- I want to understand how NB must proceed when uid!=0
It's a bit difficult with that
su
command. As far as I know the kernelSU developer has somehow redefined it's nature. Normallysu
changes the uid to someone else, sosu $uid ...
changes to that uid and executes the given command, or it swithces to that uid if no command given. KernelSU redefines it assu==sh
.With standard su
su 0
is the same assu
, because 0 is the default uid.With a standard su, if not using 0, you would need to know the other uid and use that explicitely. E.g. if uid is set to 100 , you need to execute commands with
su 100
, to run the commands on that uid. If you would usesu
, it would run the command as uid=0 instead, so not what you want.What's the behavior of kernelSU su command without the uid parameter? Does it default to the configured uid?
I tried to test this:
- I changed the Termux kernelSU profile to adb (which uses uid/gid=2000)
- I tried to execute su via /system/bin/su (a simple su uses a command from the Termux installation), but I don't have permission to do so, it is owned by root:shell and uses rwxr-xr-x, so this part should work Termux is not a good test platform, it has too many specialties...I probably should use something simpler. Or may be directly use NB
If you cat the su in Termux, you will find:
#!/data/data/com.termux/files/usr/bin/sh
unset LD_LIBRARY_PATH LD_PRELOAD
for p in /sbin/su /system/sbin/su /system/bin/su /system/xbin/su /su/bin/su /magisk/.core/bin/su
do
if [ -x $p ]; then
# The su tool may require programs in PATH:
PATH=/sbin:/sbin/su:/su/bin:/su/xbin:/system/bin:/system/xbin \
exec $p "$@"
fi
done
echo "No su program found on this device. Termux"
echo "does not supply tools for rooting, see e.g."
echo "http://www.androidcentral.com/root for"
echo "information about rooting Android."
exit 1
It unset the library set by Termux. But if you use Termux su to execute su when I using system template, it will be no error.
But I can execute /system/bin/su directly when I use default profile.
I am debugging now...
as profile I use adb, which is uid/gid=2000, no capabilities (not sure which are needed)
before any checking takes place, libsu creates a shell first and this fails with:
java.io.IOException: Cannot run program "su": error=13, Permission denied
If I assign adb profile to Shell (com.android.shell) it behaves the same. It cannot execute su. Not sure why that adb profile exists. It's not something I would want for an adb shell.
If I use a custom kernelSU profile, based on adb but with all capabilities added, libsu still cannot create a shell.
So for now it's not NB's fault. If libsu cannot create a privileged shell there is no chance to proceed.
Currently, I don't understand, why libsu cannot create a shell...
I can execute the su that doesn't seemed to be existing? I know KernelSU do hook in somewhere like vfs read file, so?
for me it works with this profile:
this was wrong...
the real profile I used in the test probably had all capabilities enabled.
For some reason changing the profile capabilities is not always accepted (I swear I saved them! :-) ). But in my current tests it was still like in the screen shot.
I guess that starting debug via IDE didn't always kill the app first.
I now did some manual tests without the IDE.
With capabilities like in the screenshot a backup creates an empty directory and there is no properties file. Then NB is hanging.
The reason is that nsenter doesn't work, because it doesn't see
/proc/1
.
If I enable all capabilities, it seems to work, at least I can create a backup. Though the first backup only had apk and external_data, not sure what exactly happened. While writing this I started NB again (which gave me the splash screen) and created the backup again and this time all parts were created. I'm sure I killed and restarted NB after switching to the full capabilities profile. Perhaps we need to wait after changing the profile...or another event must happen before it's really accepted by the system. Interesting, that apk and external worked, this probably means the mount didn't work, yet.
Someone heeds to find out which capabilities are necessary. Must be one that is not listed in the screenshot.
interesting...
I generally think Termux is not a good environment to test such things, it probably plays a lot of tricks. I usually prefer the builtin terminal. Or may be an ssh login.
NB has it's own terminal just for that reason. This way you can execute commands exactly like they are executed by NB, including the wrapping in su and nsenter and with the kernelSU profile etc.
OTOH it's not suitable to find out how these root commands should work.
change a few lines to make uid!=0 pass the check
it seems this would not help.
As analyzed here: https://github.com/NeoApplications/Neo-Backup/issues/796#issuecomment-1793219577
libsu checks explicitly for uid=0 and only then keeps the su shell. Otherwise it starts a simple sh shell instead, which cannot do root commands. Note, in the usual case commands are executed by that shell.
Theoretically it would be possible to reimplement all the things libsu does for us. But reinventing the wheel is not really what we want to do.
I think, you should convince the dev of libsu that uid > 0 can still be privileged with KSU. NB would automatically work then... Though I'm not sure how the alternative root check should work.
The whole thing is a result from the fact that kernelSU redefines the su command (at least if su without an uid does not switch to uid=0, not sure about that).
I can execute the su that doesn't seemed to be existing?
please try /system/bin/su outside of Termux... Termux seems to inject libraries, that's why the corresponding environment vars are cleared in the script. The point is, Termux tries to provide a linux environment.
A simple terminal should not do such things. The behavior would be different.
Try the command /system,/bin/su -c id
to see which uid the resulting shell uses, if you give the terminal uid > 0.
I could create a pumpkin (=test) apk, that simply omits the root check. But as I said, I'm quite sure that libsu will not work then. I can also try to not use the usual libsu commands at all (not sure if I want to do that, maybe it's reinventing the whole thing, at least it will be slower, though that doesn't matter much for a proof of concept).
Description when using KernelSU App Profile, and set uid != 1 App shows Non-Root. I think I grant enough permission for backup apps.
Steps To Reproduce
Expected behavior Go to Main Page
Screenshots
System Information(please complete the following information):
Additional Notes
If you're on the latest Test version(from the TG-Channel or Matrix-Room) please report there directly, not here.
If you're on the latest github version:
If you're not on the latest github version. Update, then make sure that the bug is still there. If it's go further with reporting.
Thanks for reporting.