[Forensics-changes] [yara] 158/192: Implement YR_TRYCATCH in terms of __try/__catch when using the Microsoft compiler (#639)

Hilko Bengen bengen at moszumanska.debian.org
Sat Jul 1 10:31:59 UTC 2017


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag v3.6.0
in repository yara.

commit 5fd4ec80cc3bcd5095e91a156a61e29305299e59
Author: Hilko Bengen <hillu at users.noreply.github.com>
Date:   Wed May 3 17:39:15 2017 +0200

    Implement YR_TRYCATCH in terms of __try/__catch when using the Microsoft compiler (#639)
    
    * Implement YR_TRYCATCH in terms of __try/__catch when using the Microsoft compiler
    
    This fixes part of #632
    
    * Switch test-exception to a subprocess model so we can check for crashes
    
    * test-exception: Add demonstrator for #632
    
    The current behavior on Unix seems to be correct: Our signal handler
    does not seem to handle signals caused in other threads
---
 libyara/exception.h    |  24 +++++-
 tests/test-exception.c | 202 +++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 194 insertions(+), 32 deletions(-)

diff --git a/libyara/exception.h b/libyara/exception.h
index 30e4745..bffe172 100644
--- a/libyara/exception.h
+++ b/libyara/exception.h
@@ -55,7 +55,27 @@ static LONG CALLBACK exception_handler(
   return EXCEPTION_CONTINUE_SEARCH;
 }
 
-#define YR_TRYCATCH(_do_,_try_clause_, _catch_clause_)                  \
+#ifdef _MSC_VER
+
+#include <excpt.h>
+
+#define YR_TRYCATCH(_do_,_try_clause_,_catch_clause_)           \
+  do                                                            \
+  {                                                             \
+    if (_do_)                                                   \
+    {                                                           \
+      __try                                                     \
+      { _try_clause_ }                                          \
+      __except(exception_handler(GetExceptionInformation()))    \
+      { _catch_clause_ }                                        \
+    }                                                           \
+    else                                                        \
+    { _try_clause_ }                                            \
+  } while(0)
+
+#else
+
+#define YR_TRYCATCH(_do_,_try_clause_,_catch_clause_)                   \
   do                                                                    \
   {                                                                     \
     if (_do_)                                                           \
@@ -78,6 +98,8 @@ static LONG CALLBACK exception_handler(
     }                                                                   \
   } while(0)
 
+#endif
+
 #else
 
 #include <setjmp.h>
diff --git a/tests/test-exception.c b/tests/test-exception.c
index 653905b..114cdf6 100644
--- a/tests/test-exception.c
+++ b/tests/test-exception.c
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/wait.h>
 #include <signal.h>
 
 #include <yara.h>
@@ -39,16 +40,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define COUNT 128
 char wbuf[1024];
 
-int main(int argc, char **argv)
+extern char **environ;
+
+int fd;
+uint8_t* mapped_region;
+YR_RULES *rules_a, *rules_0;
+
+/*
+Set up mapped_region so that it is only partially backed by the open
+file referred to by fd. Accessing the memory beyond
+
+    mapped_region + COUNT * sizeof(wbuf) / 2
+
+should cause a signal (usually SIGBUS) to be raised.
+*/
+void setup_mmap()
 {
   char* filename = strdup("yara-testblob.XXXXXX");
-  int fd = mkstemp(filename);
+  fd = mkstemp(filename);
   int i;
 
   if (fd <= 0)
   {
     perror("Create temp file");
-    return 77;
+    exit(77);
   }
 
   unlink(filename);
@@ -61,55 +76,115 @@ int main(int argc, char **argv)
       exit(EXIT_FAILURE);
   }
 
-  uint8_t* mapped_region = mmap(
+  mapped_region = mmap(
       NULL, COUNT * sizeof(wbuf), PROT_READ, MAP_SHARED, fd, 0);
 
   if (ftruncate(fd, COUNT * sizeof(wbuf) / 2) != 0)
     exit(EXIT_FAILURE);
 
-  /*
-    mapped_region is now only partially backed by the open file
-    referred to by fd. Accessing the memory beyond
-
-        mapped_region + COUNT * sizeof(wbuf) / 2
-
-    should cause a signal (usually SIGBUS) to be raised.
-  */
-
+void setup_rules()
+{
   yr_initialize();
 
-  YR_RULES* rules_a;
-
   compile_rule(
       "rule test { strings: $a = \"aaaa\" condition: all of them }",
       &rules_a);
 
-  YR_RULES* rules_0;
-
   compile_rule(
       "rule test { strings: $a = { 00 00 00 00 } condition: all of them }",
       &rules_0);
+}
 
-  puts("Scanning for \"aaaa\"...");
+void* crasher_func (void* x)
+{
+  sleep(1);
+  int *i = 0;
+  puts("crashing process...");
+  *i = 0;
+  return NULL;
+}
 
+/* Set up a thread that will cause a null pointer dereference after one second */
+void setup_crasher()
+{
+  pthread_t t;
+  pthread_attr_t attr;
+  pthread_attr_init(&attr);
+  pthread_create(&t, &attr, &crasher_func, NULL);
+}
+
+/* Simple yr_scan_* callback function that delays execution by 2 seconds */
+int delay_callback(int message,
+    void* message_data,
+    void* user_data)
+{
+  if (message == CALLBACK_MSG_RULE_MATCHING)
+  {
+    (*(int*) user_data)++;
+  }
+  puts("callback: delaying execution...");
+  sleep(2);
+  return CALLBACK_CONTINUE;
+}
+
+/* Scan a partially backed memory map, raising an exceptions, usually SIGBUS or SIGSEGV. */
+int test_crash(int handle_exceptions)
+{
+  setup_mmap();
+  setup_rules();
+
+  puts("Scanning for \"aaaa\"...");
   int matches = 0;
 
-  /*
-    If YR_TRYCATCH is redefined like this
+  int flags = (handle_exceptions ? 0 : SCAN_FLAGS_NO_TRYCATCH);
+
+  int rc = yr_rules_scan_mem(
+      rules_a, mapped_region, COUNT * sizeof(wbuf), flags, count_matches, &matches, 0);
 
-        #define YR_TRYCATCH(_try_clause_,_catch_clause_) {_try_clause_}
+  printf("err = %d, matches = %d\n", rc, matches);
 
-    yr_rules_scan_mem() will terminate the process.
-  */
+  if (rc == ERROR_SUCCESS || matches != 0)
+    return 1;
+
+  return 0;
+}
+
+/*
+Scan memory while another thread accesses invalid memory. The signal
+for that invalid memory access should not be caught by the handler set
+up using YR_TRYCATCH.
+*/
+int test_crash_other_thread()
+{
+  setup_mmap();
+  setup_rules();
+  setup_crasher();
+
+  uint8_t mem[4096];
+  memset(mem, 'a', sizeof(mem));
+
+  puts("Scanning for \"aaaa\"...");
+  int matches = 0;
 
   int rc = yr_rules_scan_mem(
-      rules_a, mapped_region, COUNT * sizeof(wbuf), 0, count_matches, &matches, 0);
+      rules_a, mem, sizeof(mem), 0, delay_callback, &matches, 0);
 
   printf("err = %d, matches = %d\n", rc, matches);
 
   if (rc == ERROR_SUCCESS || matches != 0)
     return 1;
 
+  return 0;
+}
+
+/*
+  This tests that SIGUSR1 is not delivered when setting up SIGBUS
+  signal handling -- or during SIGBUS signal handling
+*/
+int test_blocked_signal() {
+  setup_mmap();
+  setup_rules();
+
   puts("Sending blocked SIGUSR1 to ourselves...");
 
   sigset_t set;
@@ -119,14 +194,9 @@ int main(int argc, char **argv)
   kill(getpid(), SIGUSR1);
 
   puts("Scanning for {00 00 00 00}...");
-  matches = 0;
-
-  /*
-    This tests that SIGUSR1 is not delivered when setting up SIGBUS
-    signal handling -- or during SIGBUS signal handling
-  */
+  int matches = 0;
 
-  rc = yr_rules_scan_mem(
+  int rc = yr_rules_scan_mem(
       rules_0, mapped_region, COUNT * sizeof(wbuf), 0, count_matches, &matches, 0);
 
   printf("err = %d, matches = %d\n", rc, matches);
@@ -136,3 +206,73 @@ int main(int argc, char **argv)
 
   return 0;
 }
+
+int reexec(char *program)
+{
+  char *argv[] = { program, NULL };
+  int status;
+  int pid = fork();
+  switch(pid)
+  {
+  case 0:
+    return execve(program, argv, environ);
+  case -1:
+    return -1;
+  }
+  waitpid(pid, &status, 0);
+  return status;
+}
+
+int main(int argc, char **argv)
+{
+  char *op = getenv("TEST_OP");
+  if (op == NULL)
+  {
+    int status;
+    puts("Test: crash");
+    setenv("TEST_OP", "CRASH", 1);
+    status = reexec(argv[0]);
+    if (status != 0)
+      return 1;
+
+    puts("Test: crash-no-handle");
+    setenv("TEST_OP", "CRASH-NO-HANDLE", 1);
+    status = reexec(argv[0]);
+    if (!WIFSIGNALED(status))
+    {
+      fputs("Expected subprocess to be terminated by signal\n", stderr);
+      return 1;
+    }
+
+    puts("Test: blocked-signal");
+    setenv("TEST_OP", "BLOCKED-SIGNAL", 1);
+    status = reexec(argv[0]);
+    if (status != 0)
+      return 1;
+
+    puts("Test: crash-other-thread");
+    setenv("TEST_OP", "CRASH-OTHER-THREAD", 1);
+    status = reexec(argv[0]);
+    if (!WIFSIGNALED(status))
+    {
+      fputs("Expected subprocess to be terminated by signal\n", stderr);
+      return 1;
+    }
+
+    puts("Done.");
+  }
+  else if (!strcmp(op, "CRASH"))
+    return test_crash(1);
+  else if (!strcmp(op, "CRASH-NO-HANDLE"))
+    return test_crash(0);
+  else if (!strcmp(op, "BLOCKED-SIGNAL"))
+    return test_blocked_signal();
+  else if (!strcmp(op, "CRASH-OTHER-THREAD"))
+    return test_crash_other_thread();
+  else
+  {
+    fprintf(stderr, "wrong op '%s'\n", op);
+    return 77;
+  }
+  return 0;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/forensics/yara.git



More information about the forensics-changes mailing list