[analyzer] Add VforkChecker to find unsafe code in vforked process.

This checker looks for unsafe constructs in vforked process:
function calls (excluding whitelist), memory write and returns.
This was originally motivated by a vfork-related bug in xtables package.

Patch by Yury Gribov.

Differential revision: http://reviews.llvm.org/D14014

llvm-svn: 252285
diff --git a/clang/test/Analysis/vfork.c b/clang/test/Analysis/vfork.c
new file mode 100644
index 0000000..c7a02fa
--- /dev/null
+++ b/clang/test/Analysis/vfork.c
@@ -0,0 +1,114 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,security.insecureAPI.vfork,unix.Vfork -verify -x c++ %s
+
+#include "Inputs/system-header-simulator.h"
+
+void foo();
+
+// Ensure that child process is properly checked.
+int f1(int x) {
+  pid_t pid = vfork(); // expected-warning{{Call to function 'vfork' is insecure}}
+  if (pid != 0)
+    return 0;
+
+  switch (x) {
+  case 0:
+    // Ensure that modifying pid is ok.
+    pid = 1; // no-warning
+    // Ensure that calling whitelisted routines is ok.
+    execl("", "", 0); // no-warning
+    _exit(1); // no-warning
+    break;
+  case 1:
+    // Ensure that writing variables is prohibited.
+    x = 0; // expected-warning{{This assignment is prohibited after a successful vfork}}
+    break;
+  case 2:
+    // Ensure that calling functions is prohibited.
+    foo(); // expected-warning{{This function call is prohibited after a successful vfork}}
+    break;
+  default:
+    // Ensure that returning from function is prohibited.
+    return 0; // expected-warning{{Return is prohibited after a successful vfork; call _exit() instead}}
+  }
+
+  while(1);
+}
+
+// Same as previous but without explicit pid variable.
+int f2(int x) {
+  pid_t pid = vfork(); // expected-warning{{Call to function 'vfork' is insecure}}
+
+  switch (x) {
+  case 0:
+    // Ensure that writing pid is ok.
+    pid = 1; // no-warning
+    // Ensure that calling whitelisted routines is ok.
+    execl("", "", 0); // no-warning
+    _exit(1); // no-warning
+    break;
+  case 1:
+    // Ensure that writing variables is prohibited.
+    x = 0; // expected-warning{{This assignment is prohibited after a successful vfork}}
+    break;
+  case 2:
+    // Ensure that calling functions is prohibited.
+    foo(); // expected-warning{{This function call is prohibited after a successful vfork}}
+    break;
+  default:
+    // Ensure that returning from function is prohibited.
+    return 0; // expected-warning{{Return is prohibited after a successful vfork; call _exit() instead}}
+  }
+
+  while(1);
+}
+
+// Ensure that parent process isn't restricted.
+int f3(int x) {
+  if (vfork() == 0) // expected-warning{{Call to function 'vfork' is insecure}}
+    _exit(1);
+  x = 0; // no-warning
+  foo(); // no-warning
+  return 0;
+} // no-warning
+
+// Unbound pids are special so test them separately.
+void f4(int x) {
+  switch (x) {
+  case 0:
+    vfork(); // expected-warning{{Call to function 'vfork' is insecure}}
+    x = 0; // expected-warning{{This assignment is prohibited after a successful vfork}}
+    break;
+
+  case 1:
+    {
+      char args[2];
+      switch (vfork()) { // expected-warning{{Call to function 'vfork' is insecure}}
+      case 0:
+        args[0] = 0; // expected-warning{{This assignment is prohibited after a successful vfork}}
+        exit(1);
+      }
+      break;
+    }
+
+  case 2:
+    {
+      pid_t pid;
+      if ((pid = vfork()) == 0) // expected-warning{{Call to function 'vfork' is insecure}}
+        while(1); // no-warning
+      break;
+    }
+  }
+  while(1);
+} //no-warning
+
+
+void f5() {
+  // See "libxtables: move some code to avoid cautions in vfork man page"
+  // (http://lists.netfilter.org/pipermail/netfilter-buglog/2014-October/003280.html).
+  if (vfork() == 0) { // expected-warning{{Call to function 'vfork' is insecure}}
+    execl("prog", "arg1", 0); // no-warning
+    exit(1);  // expected-warning{{This function call is prohibited after a successful vfork}}
+  }
+}
+