<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>