Android エクスプロイトRage Against The Cage の実装を調べています。その背後にある考え方は、次に Android Debug Bridge (ADB) デーモンがその権限をrootからshellにドロップしようとしたときに、への呼び出しが失敗して実行を継続できるようRLIMIT_NPROC
に、シェルUIDに到達するために必要な数のプロセスを作成することです。 rootとして(このバグは、続行する前に呼び出しの結果を確認することで修正されています)。setuid()
setuid()
setrlimit()
ドキュメントによると、RLIMIT_NPROC
次のように定義されています。
呼び出しプロセスの実ユーザー ID に対して作成 できるプロセス (より正確には、Linux ではスレッド) の最大数[強調] 。この制限に達すると、fork(2) はエラー EAGAIN で失敗します。この制限は、CAP_SYS_ADMIN または CAP_SYS_RESOURCE 機能を持つプロセスには適用されません。
さらに、エクスプロイトは次のように実装されました。
/* 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;
}
}
}
したがって、RLIMIT_NPROC
「作成できるプロセスの最大数」として定義されます — 「同時に実行する」ではなく、作成されます — 実装は、2 番目のフォークによって作成されたすべての子プロセスを終了することによって定義されます。
まず第一に、UID ごとに作成されるプロセスの数を制限することがどのように機能するのか理解できません (そのカウントをリセットするには、時々マシンを再起動する必要がありますよね?)。第二に、エクスプロイトをリバース エンジニアリングし、上記のものと同等の実装を取得した人物でさえ、RLIMIT_NPROC
異なる定義をしています。
[エクスプロイト]は、特定の UID で実行できるプロセスの数を定義する値である RLIMIT_NPROC max を利用します。
とはいえ、RLIMIT_NPROC は実際にどのように機能するのでしょうか? どちらの定義がより正確ですか?