SuperSU: the "dumpstate" situation
Posted by Chainfire on 30-01-2013 at 15:45:00 - Comments: 141 - Views: 79179
Project: SuperSU - Tags: Android Good news Developer tools
Project: SuperSU - Tags: Android Good news Developer tools
A few days ago, I released SuperSU v1.00. Shortly after, it became apparent a number of users were suffering from an issue where dumpstate would request superuser access. Neither accepting nor denying dumpstate would really help, and for some users this made their phone completely unusable.
Unfortunately, I was unable to properly reproduce the problem by itself, but after a while I did figure that running dumpstate from ADB shell gave at least some insight into the problem.
After a quick investigation on how to counter the problem,I released a minor update to SuperSU: v1.01. This would stop the dumpstate popup from occurring, but would still log it.
Now after further investigation, all on the matter is clear, and v1.02 has just been released to XDA and Play. This one completely blacklists dumpstate, su will just pretend the call didn't happen.
Interestingly, if you were suffering from the dumpstate issue, this means you already had processes running that were crashing in the background. In the past it just wasn't a visible problem because SuperSU never picked up on it - but it was still already happening!
The exact how and why is a bit technical - if you're not interested in the nitty gritty, you can stop reading now.
What is dumpstate ?
dumpstate is a system tool that is called when a Dalvik process crashes, and outputs all sorts of information that ends up in a log file on your device.
Initially I thought the new SuperSU version was causing the dumpstate calls, as they were not a problem before v1.00. This is however not the case.
Why does dumpstate call su ?
If you look at the dumpstate source, it calls su to perform some commands that may produce useful debug information. Those commands will not work if you don't have a su binary installed, and even then, most of those commands are not present on most production devices. For by far most Android users, these commands thus do not add anything useful - but they don't do anything harmful either.
I assume this situation differs during Android device development, where these commands might actually work and produce valuable additional output in the logs.
If dumpstate always called su, why didn't we it popup in older SuperSU versions ?
As you might have read in the changelogs, the su binary's parameter parsing has been adjusted in v1.00, to be more compatible with Superuser's new style of parameter passing, as well as other non-Android su binaries.
dumpstate uses the su syntax for Android's own su binary (yes, there is one, though you will not find it on production devices). Interestingly, that su binary uses a syntax that isn't supported by any other su binary I know of - on either Android or other OS's. If you're surprised at this, you haven't been working with Google long enough ;)
In older versions of SuperSU, the su binary would encounter this syntax, deem it unworthy, and just ignore the call. With the new parameter parsing in both SuperSU as well as Superuser, the parameters passed by dumpstate will not be ignored, though the commands are not executed in the way dumpstate expects.
As such, the commands still fail, but this time around SuperSU does not ignore the call, but presents you with an authentication popup instead.
Note that SuperSU v1.02 does support Google's su syntax as well, but dumpstate still doesn't work (see further below) - I added it purely in case other apps may use it now or in the future.
So why don't we have dumpstate popups with Superuser ?
From my short tests with Superuser, triggering dumpstate didn't produce any popups to grant access, though I was informed by toast notification that access was granted. This is probably because dumpstate already runs with shell permissions, and Superuser auto-grants the shell user root access. In my opinion, that is a terrible idea, but it is how Superuser currently works (and not everybody may agree on my opinion here).
Note that with Superuser, the commands dumpstate tries to execute don't run either - Superuser's su binary also doesn't work with the syntax dumpstate uses.
That still doesn't explain why neither granting nor denying dumpstate fixes the issue !
For that we need to go deeper into the internals of both SuperSU and dumpstate.
When SuperSU's su binary processes a su request, it may be that some code needs to be executed by su that the parent process does not logically need to wait for. In that case, su may spin off a separate process to do this work while the parent process can continue its own operation. This is actually a very effective optimization, and one of the reasons SuperSU can be so fast (I'm sure everybody will start doing this now, hehe).
One of the things dumpstate does is gather information about all the processes running. It does this through a readdir() loop of /proc. And for each process found, it runs a su call. Yes, dumpstate is modifying a collection while iterating over it, which is often a bad idea. Normally, the su call (and all sub-processes) would be finished before control is returned to dumpstate and the next call to readdir() occurs, and there would be little to worry about. However, as SuperSU's su may spawn a new process to do background work, this background process is then picked up by the readdir() loop. In turn, that new entry triggers a new su call, which may trigger a new spin-off process, which may trigger a new su call, etc.
Essentially we end up with an infinite loop of su calls, making your device completely unresponsive, running at 100% CPU, and draining your battery.
The solution
SuperSU's su binary is simply incompatible with dumpstate's naive su usage. While the problem would also disappear if the end-user disables both notifications and logging for dumpstate, and I could certainly hardcode that into the su binary, the commands executed by dumpstate (even with 1.02's support for the syntax) will fail for by far most Android users (even if just counting rooted users).
I don't believe in hardcoding in that way, though. As such I have done the only other option left to me: dumpstate is now the first and only process that is completely blacklisted in SuperSU. Every request from dumpstate will simply be denied, valid or not.
Unfortunately, I was unable to properly reproduce the problem by itself, but after a while I did figure that running dumpstate from ADB shell gave at least some insight into the problem.
After a quick investigation on how to counter the problem,I released a minor update to SuperSU: v1.01. This would stop the dumpstate popup from occurring, but would still log it.
Now after further investigation, all on the matter is clear, and v1.02 has just been released to XDA and Play. This one completely blacklists dumpstate, su will just pretend the call didn't happen.
Interestingly, if you were suffering from the dumpstate issue, this means you already had processes running that were crashing in the background. In the past it just wasn't a visible problem because SuperSU never picked up on it - but it was still already happening!
The exact how and why is a bit technical - if you're not interested in the nitty gritty, you can stop reading now.
What is dumpstate ?
dumpstate is a system tool that is called when a Dalvik process crashes, and outputs all sorts of information that ends up in a log file on your device.
Initially I thought the new SuperSU version was causing the dumpstate calls, as they were not a problem before v1.00. This is however not the case.
Why does dumpstate call su ?
If you look at the dumpstate source, it calls su to perform some commands that may produce useful debug information. Those commands will not work if you don't have a su binary installed, and even then, most of those commands are not present on most production devices. For by far most Android users, these commands thus do not add anything useful - but they don't do anything harmful either.
I assume this situation differs during Android device development, where these commands might actually work and produce valuable additional output in the logs.
If dumpstate always called su, why didn't we it popup in older SuperSU versions ?
As you might have read in the changelogs, the su binary's parameter parsing has been adjusted in v1.00, to be more compatible with Superuser's new style of parameter passing, as well as other non-Android su binaries.
dumpstate uses the su syntax for Android's own su binary (yes, there is one, though you will not find it on production devices). Interestingly, that su binary uses a syntax that isn't supported by any other su binary I know of - on either Android or other OS's. If you're surprised at this, you haven't been working with Google long enough ;)
In older versions of SuperSU, the su binary would encounter this syntax, deem it unworthy, and just ignore the call. With the new parameter parsing in both SuperSU as well as Superuser, the parameters passed by dumpstate will not be ignored, though the commands are not executed in the way dumpstate expects.
As such, the commands still fail, but this time around SuperSU does not ignore the call, but presents you with an authentication popup instead.
Note that SuperSU v1.02 does support Google's su syntax as well, but dumpstate still doesn't work (see further below) - I added it purely in case other apps may use it now or in the future.
So why don't we have dumpstate popups with Superuser ?
From my short tests with Superuser, triggering dumpstate didn't produce any popups to grant access, though I was informed by toast notification that access was granted. This is probably because dumpstate already runs with shell permissions, and Superuser auto-grants the shell user root access. In my opinion, that is a terrible idea, but it is how Superuser currently works (and not everybody may agree on my opinion here).
Note that with Superuser, the commands dumpstate tries to execute don't run either - Superuser's su binary also doesn't work with the syntax dumpstate uses.
That still doesn't explain why neither granting nor denying dumpstate fixes the issue !
For that we need to go deeper into the internals of both SuperSU and dumpstate.
When SuperSU's su binary processes a su request, it may be that some code needs to be executed by su that the parent process does not logically need to wait for. In that case, su may spin off a separate process to do this work while the parent process can continue its own operation. This is actually a very effective optimization, and one of the reasons SuperSU can be so fast (I'm sure everybody will start doing this now, hehe).
One of the things dumpstate does is gather information about all the processes running. It does this through a readdir() loop of /proc. And for each process found, it runs a su call. Yes, dumpstate is modifying a collection while iterating over it, which is often a bad idea. Normally, the su call (and all sub-processes) would be finished before control is returned to dumpstate and the next call to readdir() occurs, and there would be little to worry about. However, as SuperSU's su may spawn a new process to do background work, this background process is then picked up by the readdir() loop. In turn, that new entry triggers a new su call, which may trigger a new spin-off process, which may trigger a new su call, etc.
Essentially we end up with an infinite loop of su calls, making your device completely unresponsive, running at 100% CPU, and draining your battery.
The solution
SuperSU's su binary is simply incompatible with dumpstate's naive su usage. While the problem would also disappear if the end-user disables both notifications and logging for dumpstate, and I could certainly hardcode that into the su binary, the commands executed by dumpstate (even with 1.02's support for the syntax) will fail for by far most Android users (even if just counting rooted users).
I don't believe in hardcoding in that way, though. As such I have done the only other option left to me: dumpstate is now the first and only process that is completely blacklisted in SuperSU. Every request from dumpstate will simply be denied, valid or not.