X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2Flizard-safe.c;h=0473e34ae7270215267adb6b59e342eb43140485;hb=baa9f9a3368c8d318b9711340727f822d8fc8a34;hp=dcc01d11f59a6a69528eac1fd75f86f867230d35;hpb=54952ff4cd9e28755d0fb0d38e2dab3c1299a6ab;p=libucw.git diff --git a/lib/lizard-safe.c b/lib/lizard-safe.c index dcc01d11..0473e34a 100644 --- a/lib/lizard-safe.c +++ b/lib/lizard-safe.c @@ -8,11 +8,10 @@ */ #include "lib/lib.h" +#include "lib/threads.h" #include "lib/lizard.h" -#include #include -#include #include #include #include @@ -21,7 +20,6 @@ struct lizard_buffer { uns len; void *ptr; - struct sigaction *old_sigsegv_handler; }; struct lizard_buffer * @@ -30,24 +28,22 @@ lizard_alloc(void) struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer)); buf->len = 0; buf->ptr = NULL; - buf->old_sigsegv_handler = xmalloc(sizeof(struct sigaction)); - handle_signal(SIGSEGV, buf->old_sigsegv_handler); + handle_signal(SIGSEGV); return buf; } void lizard_free(struct lizard_buffer *buf) { + unhandle_signal(SIGSEGV); if (buf->ptr) - munmap(buf->ptr, buf->len + PAGE_SIZE); - unhandle_signal(SIGSEGV, buf->old_sigsegv_handler); - xfree(buf->old_sigsegv_handler); + munmap(buf->ptr, buf->len + CPU_PAGE_SIZE); xfree(buf); } static void lizard_realloc(struct lizard_buffer *buf, uns max_len) - /* max_len needs to be aligned to PAGE_SIZE */ + /* max_len needs to be aligned to CPU_PAGE_SIZE */ { if (max_len <= buf->len) return; @@ -55,12 +51,12 @@ lizard_realloc(struct lizard_buffer *buf, uns max_len) max_len = 2*buf->len; if (buf->ptr) - munmap(buf->ptr, buf->len + PAGE_SIZE); + munmap(buf->ptr, buf->len + CPU_PAGE_SIZE); buf->len = max_len; - buf->ptr = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + buf->ptr = mmap(NULL, buf->len + CPU_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (buf->ptr == MAP_FAILED) - die("mmap(anonymous): %m"); - if (mprotect(buf->ptr + buf->len, PAGE_SIZE, PROT_NONE) < 0) + die("mmap(anonymous, %d bytes): %m", (uns)(buf->len + CPU_PAGE_SIZE)); + if (mprotect(buf->ptr + buf->len, CPU_PAGE_SIZE, PROT_NONE) < 0) die("mprotect: %m"); } @@ -68,36 +64,39 @@ static jmp_buf safe_decompress_jump; static int sigsegv_handler(int signal UNUSED) { - log(L_ERROR, "SIGSEGV caught in lizard_decompress()"); longjmp(safe_decompress_jump, 1); return 1; } -int -lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length, byte **ptr) +byte * +lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length) /* Decompresses in into buf, sets *ptr to the data, and returns the * uncompressed length. If an error has occured, -1 is returned and errno is * set. The buffer buf is automatically reallocated. SIGSEGV is caught in * case of buffer-overflow. The function is not re-entrant because of a * static longjmp handler. */ { - uns lock_offset = ALIGN(expected_length + 3, PAGE_SIZE); // +3 due to the unaligned access + uns lock_offset = ALIGN_TO(expected_length + 3, CPU_PAGE_SIZE); // +3 due to the unaligned access if (lock_offset > buf->len) lizard_realloc(buf, lock_offset); - volatile sh_sighandler_t old_handler = signal_handler[SIGSEGV]; - signal_handler[SIGSEGV] = sigsegv_handler; - int len; + volatile sh_sighandler_t old_handler = set_signal_handler(SIGSEGV, sigsegv_handler); + byte *ptr; if (!setjmp(safe_decompress_jump)) { - *ptr = buf->ptr + buf->len - lock_offset; - len = lizard_decompress(in, *ptr); + ptr = buf->ptr + buf->len - lock_offset; + int len = lizard_decompress(in, ptr); + if (len != (int) expected_length) + { + ptr = NULL; + errno = EINVAL; + } } else { - *ptr = NULL; - len = -1; + log(L_ERROR, "SIGSEGV caught in lizard_decompress()"); + ptr = NULL; errno = EFAULT; } - signal_handler[SIGSEGV] = old_handler; - return len; + set_signal_handler(SIGSEGV, old_handler); + return ptr; }