[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