ChainsDD / su-binary

su binary for android Superuser
Other
452 stars 320 forks source link

su: Permission denied #10

Open zjw opened 12 years ago

zjw commented 12 years ago

Superuser: v3.0.7 (from the play store) su-binary: v3.0.3.2 Phone: galaxy nexus running stock aosp 4.0.4 (leaked build IMM30B)

I installed SSHelper from the play store. I can ssh into the phone. When I try to run "/system/bin/su", it hangs for 20 sec., and then responds, "Permission denied". The Superuser app on the phone never pops up requesting permission.

logcat:

05-05 15:29:39.855: E/su(2070): sudb - Opening database
05-05 15:29:39.855: E/su(2070): sudb - Database opened
05-05 15:29:39.855: E/su(2070): sudb - Database closed
05-05 15:29:39.863: E/ActivityManager(174): Activity Manager Crash
05-05 15:29:39.863: E/ActivityManager(174): java.lang.NullPointerException
05-05 15:29:39.863: E/ActivityManager(174):     at android.content.Intent.readFromParcel(Intent.java:6146)
05-05 15:29:39.863: E/ActivityManager(174):     at android.content.Intent.(Intent.java:6126)
05-05 15:29:39.863: E/ActivityManager(174):     at android.content.Intent$1.createFromParcel(Intent.java:6117)
05-05 15:29:39.863: E/ActivityManager(174):     at android.content.Intent$1.createFromParcel(Intent.java:6115)
05-05 15:29:39.863: E/ActivityManager(174):     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:298)
05-05 15:29:39.863: E/ActivityManager(174):     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1545)
05-05 15:29:39.863: E/ActivityManager(174):     at android.os.Binder.execTransact(Binder.java:338)
05-05 15:29:39.863: E/ActivityManager(174):     at dalvik.system.NativeStart.run(Native Method)
05-05 15:29:59.964: E/su(2070): select failed with 2: No such file or directory
05-05 15:29:59.964: W/su(2070): request rejected (10091->0 /system/bin/sh)
05-05 15:29:59.964: E/ActivityManager(174): Activity Manager Crash
05-05 15:29:59.964: E/ActivityManager(174): java.lang.NullPointerException
05-05 15:29:59.964: E/ActivityManager(174):     at android.content.Intent.readFromParcel(Intent.java:6146)
05-05 15:29:59.964: E/ActivityManager(174):     at android.content.Intent.(Intent.java:6126)
05-05 15:29:59.964: E/ActivityManager(174):     at android.content.Intent$1.createFromParcel(Intent.java:6117)
05-05 15:29:59.964: E/ActivityManager(174):     at android.content.Intent$1.createFromParcel(Intent.java:6115)
05-05 15:29:59.964: E/ActivityManager(174):     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:298)
05-05 15:29:59.964: E/ActivityManager(174):     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1545)
05-05 15:29:59.964: E/ActivityManager(174):     at android.os.Binder.execTransact(Binder.java:338)
05-05 15:29:59.964: E/ActivityManager(174):     at dalvik.system.NativeStart.run(Native Method)
git-core commented 12 years ago

I've dug AOSP sources again around reading of categories in readFromParcel, the last change here occurred at eclair times. Thus, it smells like your ROM might have either wrong value of the ro.build.version.sdk property or something wrong in property_get. And I can't believe in the latter. So, what's the value of the property?

zjw commented 12 years ago

ro.build.version.sdk=15

Keep in mind (and I might not have been clear about this before) that the Superuser app & su-binary function normally, except under the conditions described above (i.e., ROM Manager, Ti Backup, etc., work fine).

I don't know what is different when /system/bin/su is used in conjunction with the SSHelper app. That app simply starts a dropbear ssh server on the phone which listens for incoming ssh connections and starts an unprivileged shell for each new connection. Running /system/bin/su from within the shell results in the errors recorded above, and access is denied.

I have found a work-around that isn't difficult. The SSHelper app has a crude terminal feature built into it. If I run /system/bin/su from within that terminal on the phone, the Superuser app pops up requesting permission. Once I grant permission there (and tell it to remember it), then I am able to remotely ssh into the phone, and I am able to successfully run /system/bin/su. Nonetheless, there is no logging of my remote access recorded within the Superuser app's access logs, because the su-binary's attempts to send log notices to the Superuser app are continuing to fail.

git-core commented 12 years ago

Could you try to apply the patch https://gist.github.com/2642648 on top of the master tree and post log w/ sdk_version here?

rovo89 commented 12 years ago

I have/had a similar issue. After upgrading to the latest Siyah kernel, I suddenly saw soft reboots (restart of the Zygote process, including boot animation, but no real restart) every time when I unplugged my phone, either from my PC or from the charger.

After some hours of debugging, I think I found the problem.

This occurs when BetterBatteryStats tries to execute "dumpsys alarm" and has never been granted permissions for that (i.e. there is no matching entry in permissions.sqlite). It doesn't occur if I su to app_123 and try to execute the command from there. Actually, the crash happens 20 seconds after unplugging. This is because after this time, the app is considered as hanging and gets killed (which seems to bring down the whole system). Once I lowered the timeout for the "select" function a bit, at least it didn't crash anymore, but as shown above, the request was rejected without prompt. Also, there was no entry in the "apps" tab, from which I could have granted the permission for the next time.

The key point seems to be the "su" attempt by BBS is performed inside onReceive for the "power disconnected" broadcast. The intent sent by su to Superuser actually comes through very well, but only after the timeout and then it's too late. So probably broadcast intents are handled one after the other and thus the prompt can never happen from within another broadcast receiver.

As mentioned, the intent still gets processed after the timeout, but the prompt checks whether it can write to the socket. Since the timeout is over, the socket file was deleted at that time, the check fails and the prompt is not shown. I have tested to disable this check, which is definitely not perfect, but at least shows the prompt after the timeout. When I save my choice there, it gets saved to the database and there is no more need to show the prompt next time.

My idea to do this in a better way would to drastically lower the timeout in su, maybe to 3 seconds. Within that time, Superuser has to respond either with "ALLOW", "DENY" (possible so fast if automatic reply is active) or "WAIT". The latter would be sent by Superuser in case the prompt needs to be shown. The socket connection in su would then wait for an additional "ALLOW"/"DENY" coming through the same connection. In cases like the one I described, Superuser could not reply anything, so "select" would fail and su could go forward denying the request (this time). As soon as Superuser then gets the request intent, it could still show the prompt, maybe with an additional sentence that a background app required root access and that the choice will be valid from the next time this background app tries to gain root permissions.

What do you think of this?

git-core commented 12 years ago

Well, it seems there is no need for adding new response like "WAIT". select you mentioned waits for a connect from Superuser, not a data arrival. Superuser may perform connect ASAP, e.g. by literally first action in its request receiver, and then do the rest of its job. I'm not sure it will help in the case you described, but an additional response won't help either. You may try this approach and check if it helps.

rovo89 commented 12 years ago

Let me see if I still remember what I found out... I think the problem was that the Intent didn't get through to Superuser in time if su was called from a BroadcastReceiver (like BBS does on unplugging for example). I assume this could be due to a deadlock which would prevent two BroadcastReceivers in one process running at the very same time.

The control flow should look like this: System notices unplugging -> calls BBS BroadcastReceiver -> calls su -> sends intent to Superuser -> answers "allow" -> executes command -> returns to BroadcastReceiver. Now if the intent to Superuser is blocked, su will interpret this as a denial. Only once the BBS receiver has returned, the request will get through to Superuser. But then it realizes that it makes no sense to show the dialog anymore because the request is already outdated.

The suggestion with the "WAIT" response was meant as a way to signal that Superuser will need some time (like 10 seconds) until it will give the approval/denial, but generally it did get the intent and is interacting with the user. This is in contrast to a deadlock sitation where Superuser doesn't even know about the request. This "WAIT" response could then reduce the time su waits for Superuser, and in turn Superuser could still show the request even if is outdated, thus giving the user a chance to set the response for the next time.

git-core commented 12 years ago

Well, my previous note was about the "WAIT" response only. Again, only thing su needs from Superuser is an incoming connection. After the connection is established su "knows" that Superuser is alive, so waits indefinitely in the read syscall for response. Thus, the incoming connection from Superuser behaves exactly as "WAIT" you proposed. Unfortunately, current code in Superuser establishes the connection after it gets user's answer.

BBS is quite different issue. I can't help with it rather than saying it shall be fixed one way or another.

rovo89 commented 12 years ago

Ah, sorry. Now I get it.

I think what I tried was to decrease the timeout in su (because 20 seconds is the timeout for ANRs) and remove the finish() in SuRequestActivity when the connection to the socket failed. Of course this requires more error handling (especially, it shouldn't attempt to write to the "null" socket then), but for my case, it did what it should: The app was frozen for the shorter timeout, then the request was denied (because Superuser didnt respond) and then the request dialog was shown. I could select to allow the request, and the next time when I unplugged the phone, root permissions were granted immediately because the app was in the database (which it wasn't previously, because SuRequestActivity quit early as it couldn't open the socket).

git-core commented 12 years ago

One note: Superuser 3.1.3 makes the connection before it prompts the user due to the authentication data are passed over the socket, not in the intent as older versions did.