Changeset: 60ac438a9b58 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=60ac438a9b58
Modified Files:
        sql/backends/monet5/UDF/capi/Tests/capi03.sql
        sql/backends/monet5/UDF/capi/capi.c
Branch: jitudf
Log Message:

Use pthread_sigmask to stop blocking SIGSEGV/SIGBUS in C UDFs.

We want to catch these signals so we can detect and prevent writing to input 
BATs using mprotect.


diffs (208 lines):

diff --git a/sql/backends/monet5/UDF/capi/Tests/capi03.sql 
b/sql/backends/monet5/UDF/capi/Tests/capi03.sql
--- a/sql/backends/monet5/UDF/capi/Tests/capi03.sql
+++ b/sql/backends/monet5/UDF/capi/Tests/capi03.sql
@@ -50,20 +50,35 @@ SELECT capi03(i) FROM integers;
 
 ROLLBACK;
 
--- START TRANSACTION;
+START TRANSACTION;
 
--- # Modify input data
--- CREATE FUNCTION capi03(inp INTEGER) RETURNS INTEGER LANGUAGE C {
---     inp.data[0] = 10;
---     result->initialize(result, inp.count);
---     for(size_t i = 0; i < inp.count; i++) {
---             result->data[i] = inp.data[i] * 2;
---     }
--- };
+# Modify input data
+CREATE FUNCTION capi03(inp INTEGER) RETURNS INTEGER LANGUAGE C {
+       inp.data[0] = 10;
+       result->initialize(result, inp.count);
+       for(size_t i = 0; i < inp.count; i++) {
+               result->data[i] = inp.data[i] * 2;
+       }
+};
 
--- CREATE TABLE integers(i INTEGER);
--- INSERT INTO integers VALUES (1), (2), (3), (4), (5);
+CREATE TABLE integers(i INTEGER);
+INSERT INTO integers VALUES (1), (2), (3), (4), (5);
 
--- SELECT capi03(i) FROM integers;
+SELECT capi03(i) FROM integers;
 
--- ROLLBACK;
+ROLLBACK;
+
+START TRANSACTION;
+
+# Trigger a segfault
+CREATE FUNCTION capi03(inp INTEGER) RETURNS INTEGER LANGUAGE C {
+       int x = *((int*)NULL);
+};
+
+CREATE TABLE integers(i INTEGER);
+INSERT INTO integers VALUES (1), (2), (3), (4), (5);
+
+SELECT capi03(i) FROM integers;
+
+ROLLBACK;
+
diff --git a/sql/backends/monet5/UDF/capi/capi.c 
b/sql/backends/monet5/UDF/capi/capi.c
--- a/sql/backends/monet5/UDF/capi/capi.c
+++ b/sql/backends/monet5/UDF/capi/capi.c
@@ -12,7 +12,15 @@
 
 #include "mtime.h"
 
-#include "setjmp.h"
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
 
 static __thread jmp_buf jump_buffer;
 
@@ -49,6 +57,7 @@ static void handler(int sig, siginfo_t *
        (void) sig;
        (void) si;
        (void) unused;
+       // we caught a segfault or bus error
        longjmp(jump_buffer, 1);
 }
 
@@ -61,24 +70,22 @@ typedef struct _mprotected_region {
 
 static char*
 mprotect_region(void* addr, size_t len, int flags, mprotected_region** 
regions) {
-#ifdef __APPLE__
-       // we don't mprotect on OSX for now
-       return NULL;
-#else
        mprotected_region* region;
+       int pagesize;
+       void* page_begin;
        if (len == 0) return NULL;
        // check if the region is page-aligned
-       /*
-       int pagesize = getpagesize();
-       void* page_begin = (void*)((size_t)addr - (size_t)addr % pagesize);
+       
+       pagesize = getpagesize();
+       page_begin = (void*)((size_t)addr - (size_t)addr % pagesize);
        if (page_begin != addr) {
                // data is not page-aligned
-               len += (addr - page_begin);
+               len += ((size_t)addr - (size_t)page_begin);
                addr = page_begin;
        }
        // page align len
        len = len % pagesize == 0 ? len : len - len % pagesize + pagesize;
-*/
+
        region = GDKmalloc(sizeof(mprotected_region));
        if (!region) {
                return MAL_MALLOC_FAIL;
@@ -92,7 +99,6 @@ mprotect_region(void* addr, size_t len, 
        region->next = *regions;
        *regions = region;
        return NULL;
-#endif
 }
 
 static char*
@@ -202,7 +208,7 @@ GENERATE_BASE_HEADERS(cudf_data_timestam
 const char *debug_flag = "capi_use_debug";
 const char *cc_flag = "capi_cc";
 
-#define JIT_COMPILER_NAME "clang"
+#define JIT_COMPILER_NAME "cc"
 
 static size_t GetTypeCount(int type, void* struct_ptr);
 static void* GetTypeData(int type, void* struct_ptr);
@@ -252,7 +258,8 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
 
        lng initial_output_count = -1;
 
-       struct sigaction sa;
+       struct sigaction sa, oldsa, oldsb;
+       sigset_t signal_set;
 
 #ifdef NDEBUG
        int debug_build = GDKgetenv_istrue(debug_flag) || 
GDKgetenv_isyes(debug_flag);
@@ -267,6 +274,16 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
 
        (void) cntxt;
 
+       // we need to be able to catch segfaults and bus errors
+       // so we can work with mprotect to prevent UDFs from changing
+       // the input data
+
+       // we remove them from the pthread_sigmask
+       (void) sigemptyset(&signal_set);
+       (void) sigaddset(&signal_set, SIGSEGV);
+       (void) sigaddset(&signal_set, SIGBUS);
+       (void) pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
+
        memset(&sa, 0, sizeof(sa));
 
        if (!grouped) {
@@ -687,7 +704,7 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
                goto wrapup;
        } else if (ret > 0) {
                if (ret == 1) {
-                       msg = createException(MAL, "cudf.eval", "Attempting to 
write to read-only memory");
+                       msg = createException(MAL, "cudf.eval", "Attempting to 
write to the input or triggered a segfault/bus error");
                        goto wrapup;
                } else if (ret == 2) {
                        msg = createException(MAL, "cudf.eval", "Malloc failure 
in internal function!");
@@ -700,10 +717,11 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
        }
 
        // set up the signal handler for catching segfaults
+       memset(&sa, 0, sizeof(sa));
     sa.sa_flags = SA_SIGINFO;
-    sigemptyset(&sa.sa_mask);
+    sigfillset(&sa.sa_mask);
     sa.sa_sigaction = handler;
-       if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 
0) {
+       if (sigaction(SIGSEGV, &sa, &oldsa) == -1 || sigaction(SIGBUS, &sa, 
&oldsb) == -1) {
                msg = createException(MAL, "cudf.eval", "Failed to set signal 
handler: %s", strerror(errno));
                errno = 0;
                goto wrapup;
@@ -714,7 +732,7 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal
        msg = func(inputs, outputs, wrapped_GDK_malloc);
 
        // clear the signal handlers
-       if (sigaction(SIGSEGV, NULL, NULL) < 0 || sigaction(SIGBUS, NULL, NULL) 
< 0) {
+       if (sigaction(SIGSEGV, &oldsa, NULL) == -1 || sigaction(SIGBUS, &oldsb, 
NULL) == -1) {
                msg = createException(MAL, "cudf.eval", "Failed to unset signal 
handler: %s", strerror(errno));
                errno = 0;
                goto wrapup;
@@ -824,8 +842,8 @@ wrapup:
        // cleanup
        // remove the signal handler, if any was set
        if (sa.sa_sigaction) {
-               sigaction(SIGBUS, NULL, NULL);
-               sigaction(SIGSEGV, NULL, NULL);
+               sigaction(SIGSEGV, &oldsa, NULL);
+               sigaction(SIGBUS, &oldsb, NULL);
 
                memset(&sa, 0, sizeof (sa));
        }
@@ -836,6 +854,8 @@ wrapup:
                GDKfree(regions);
                regions = next;
        }
+       // block segfaults and bus errors again after we exit
+       (void) pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
        // argument names (input)
        if (args) {
                for(i = 0; i < (size_t) pci->argc; i++) {
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to