Perf + armcap fixes

* Perf is setting 'exclude_callchain_kernel' flag which requires kernels >= 3.7.
   Detect old kernels and abort archInit() if not compatible.
   TODO: See if disabling that flag at runtime for non-compatible kernels affects perf operations

* For ARM kernels running Android API <= 21, if fuzzing target links to
  libcrypto (OpenSSL), OPENSSL_cpuid_setup initialization is triggering a
  SIGILL/ILLOPC at armv7_tick(). Setups using BoringSSL (API >= 22) are
  not affected.

Signed-off-by: Anestis Bechtsoudis <anestis@census-labs.com>
diff --git a/android/Android.mk b/android/Android.mk
index ed14b08..249c6a5 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -41,6 +41,13 @@
     $(error Unsuported / Unknown APP_API '$(APP_ABI)')
   endif
 
+  # Additional libcrypto OpenSSL flags required to mitigate bug (ARM systems with API <= 21)
+  ifeq ($(APP_ABI),$(filter $(APP_ABI),armeabi))
+    OPENSSL_ARMCAP_ABI := "5"
+   else
+    OPENSSL_ARMCAP_ABI := "7"
+  endif
+
   # Upstream libunwind compiled from sources with Android NDK toolchain
   LIBUNWIND_A := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(UNW_ARCH).a
   ifeq ("$(wildcard $(LIBUNWIND_A))","")
@@ -113,6 +120,6 @@
 endif
 
 LOCAL_SRC_FILES += $(ARCH_SRCS)
-LOCAL_CFLAGS += -D_HF_ARCH_${ARCH}
+LOCAL_CFLAGS += -D_HF_ARCH_${ARCH} -DOPENSSL_ARMCAP_ABI='$(OPENSSL_ARMCAP_ABI)'
 
 include $(BUILD_EXECUTABLE)
diff --git a/linux/arch.c b/linux/arch.c
index 2518dd0..ab204e4 100644
--- a/linux/arch.c
+++ b/linux/arch.c
@@ -44,6 +44,7 @@
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/utsname.h>
 
 #include "linux/perf.h"
 #include "linux/ptrace_utils.h"
@@ -333,8 +334,49 @@
 
 bool arch_archInit(honggfuzz_t * hfuzz)
 {
-    return true;
-    if (hfuzz) {
-        return true;
+    unsigned long major = 0, minor = 0;
+    char *p = NULL;
+
+    if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
+        /*
+         * Check that linux kernel is compatible
+         *
+         * Compatibility list:
+         *  1) Perf exclude_callchain_kernel requires kernel >= 3.7
+         *     TODO: Runtime logic to disable it for unsupported kernels
+         *           if it doesn't affect perf counters processing
+         */
+        struct utsname uts;
+        if (uname(&uts) == -1) {
+            LOGMSG_P(l_FATAL, "uname() failed");
+            return false;
+        }
+
+        p = uts.release;
+        major = strtoul(p, &p, 10);
+        if (*p++ != '.') {
+            LOGMSG(l_FATAL, "Unsupported kernel version (%s)", uts.release);
+            return false;
+        }
+
+        minor = strtoul(p, &p, 10);
+        if ((major < 3) || ((major == 3) && (minor < 7))) {
+            LOGMSG(l_ERROR, "Unsupported kernel version (%s)", uts.release);
+            return false;
+        }
     }
+#if defined(__ANDROID__) && defined(__arm__)
+    /* 
+     * For ARM kernels running Android API <= 21, if fuzzing target links to 
+     * libcrypto (OpenSSL), OPENSSL_cpuid_setup initialization is triggering a
+     * SIGILL/ILLOPC at armv7_tick() due to  "mrrc p15, #1, r0, r1, c14)" instruction.
+     * Setups using BoringSSL (API >= 22) are not affected.
+     */
+    if (setenv("OPENSSL_armcap", OPENSSL_ARMCAP_ABI, 1) == -1) {
+        LOGMSG_P(l_ERROR, "setenv(OPENSSL_armcap) failed");
+        return false;
+    }
+#endif
+
+    return true;
 }