<div dir="ltr"><div>ChrootChecker tracks a chroot failed case. It will generate warning</div><div>even though chroot is used properly.</div><div><br></div><div>When finding improper using chroot, ChrootChecker doesn't stop</div>
<div>tracking. It will generate verbose warning.</div><div><br></div><div>For example, ChrootChecker will generate warnings from below code</div><div>which can switch proper using and improper using with IMPROPER_USE.</div>
<div><br></div><div>When IMPROPER_USE is not defined, 1 warning will be generated.</div><div>When IMPROPER_USE is defined, 3 warnings will be generated.</div><div><br></div><div><br></div><div>#include <stdio.h></div>
<div>#include <stdlib.h></div><div>#include <unistd.h></div><div><br></div><div>int main(int argc, char *argv[])</div><div>{</div><div> if (argc < 2) {</div><div><span class="" style="white-space:pre"> </span>fprintf(stderr, "usage: %s newroot\n", argv[0]);</div>
<div><span class="" style="white-space:pre"> </span>return 1;</div><div> }</div><div><br></div><div> if (chroot(argv[1]) < 0) {</div><div><span class="" style="white-space:pre"> </span>perror("chroot"); /** proper using and improper using */</div>
<div><span class="" style="white-space:pre"> </span>return 1;</div><div> }</div><div><br></div><div>#ifndef IMPROPER_USE</div><div> if (chdir("/") < 0) {</div><div><span class="" style="white-space:pre"> </span>perror("chdir");</div>
<div><span class="" style="white-space:pre"> </span>return 1;</div><div> }</div><div>#endif</div><div><br></div><div> if (execv("/bin/sh", argv) < 0) { /** improper using */</div><div><span class="" style="white-space:pre"> </span>perror("execv"); /** improper using */</div>
<div><span class="" style="white-space:pre"> </span>return 1;</div><div> }</div><div><br></div><div> return 0;</div><div>}</div><div><br></div><div><br></div><div>This patch will bind return value of chroot to zero. And this patch</div>
<div>will stop tracking when finding improper using chroot.</div><div><br></div><div><br></div><div>Index: lib/StaticAnalyzer/Checkers/ChrootChecker.cpp</div><div>===================================================================</div>
<div>--- lib/StaticAnalyzer/Checkers/ChrootChecker.cpp<span class="" style="white-space:pre"> </span>(revision 202679)</div><div>+++ lib/StaticAnalyzer/Checkers/ChrootChecker.cpp<span class="" style="white-space:pre"> </span>(working copy)</div>
<div>@@ -87,11 +87,13 @@</div><div> void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {</div><div> ProgramStateRef state = C.getState();</div><div> ProgramStateManager &Mgr = state->getStateManager();</div>
<div>+ SValBuilder &svalBuilder = C.getSValBuilder();</div><div>+ SVal success = svalBuilder.makeZeroVal(svalBuilder.getContext().IntTy);</div><div> </div><div> // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in </div>
<div> // the GDM.</div><div> state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);</div><div>- C.addTransition(state);</div><div>+ C.addTransition(state->BindExpr(CE, C.getLocationContext(), success));</div>
<div> }</div><div> </div><div> void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {</div><div>@@ -140,7 +142,7 @@</div><div> void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());</div>
<div> if (k)</div><div> if (isRootChanged((intptr_t) *k))</div><div>- if (ExplodedNode *N = C.addTransition()) {</div><div>+ if (ExplodedNode *N = C.generateSink()) {</div><div> if (!BT_BreakJail)</div>
<div> BT_BreakJail.reset(new BuiltinBug(</div><div> this, "Break out of jail", "No call of chdir(\"/\") immediately "</div><div><br></div></div>