I'm taking a look at the implementation of the Android exploit Rage Against The Cage. The idea behind it is that it creates as many processes as necessary to reach RLIMIT_NPROC
for the shell UID so that the next time the Android Debug Bridge (ADB) daemon tried to drop its privileges from root to shell, the call to setuid()
fails and it continues executing as root (that bug has been fixed by checking the result of the setuid()
call before proceeding).
According to setrlimit()
documentation, RLIMIT_NPROC
is defined as:
The maximum number of processes (or, more precisely on Linux, threads) that can be created [emphasis mine] for the real user ID of the calling process. Upon encountering this limit, fork(2) fails with the error EAGAIN. This limit is not enforced for processes that have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.
Moreover, this is how the exploit was implemented:
/* generate many (zombie) shell-user processes so restarting
* adb's setuid() will fail.
* The whole thing is a bit racy, since when we kill adb
* there is one more process slot left which we need to
* fill before adb reaches setuid(). Thats why we fork-bomb
* in a seprate process.
*/
if (fork() == 0) { // 'true' for the child
close(pepe[0]);
for (;;) {
if ((p = fork()) == 0) {
exit(0); // child exits (???)
} else if (p < 0) {
if (new_pids) {
printf("\n[+] Forked %d childs.\n", pids);
new_pids = 0;
write(pepe[1], &c, 1);
close(pepe[1]);
}
} else {
++pids;
}
}
}
So, RLIMIT_NPROC
is defined as the "maximum number of processes that can be created" — created, not "execute at the same time" — and the implementation seconds that definition by terminating every child process created by the second fork.
First of all, I can't understand how limiting the number of process created per UID could possibly work (we'd have to restart our machines from time to time to reset that count, wouldn't we?). Second, even the guy who reverse engineered the exploit, obtaining an implementation equivalent to the one shown above, defines the RLIMIT_NPROC
differently:
It [the exploit] takes advantage of RLIMIT_NPROC max, which is a value that defines how many processes a given UID can have running.
That said, how RLIMIT_NPROC actually works? Which definition is more precise?