From 159f3fd2f4b044788fc71208855ed1a846b20949 Mon Sep 17 00:00:00 2001 From: Robert Spalek Date: Tue, 15 Jun 2004 09:16:13 +0000 Subject: [PATCH] - low-level safe version of lizard_decompress() put into an extra source file - use M_PRIVATE instead of M_SHARED - use PROT_NONE instead of PROT_READ and only set/clear it for one page before/after the operation instead of doing it for all the array - errno is set instead of returning different negative values - use longjmp in the signal handler instead of die() and return -1 - use macro ALIGN() --- lib/lizard-safe.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 lib/lizard-safe.c diff --git a/lib/lizard-safe.c b/lib/lizard-safe.c new file mode 100644 index 00000000..fb45f8bf --- /dev/null +++ b/lib/lizard-safe.c @@ -0,0 +1,81 @@ +/* + * LiZaRd -- Fast compression method based on Lempel-Ziv 77 + * + * (c) 2004, Robert Spalek + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#include "lib/lib.h" +#include "lib/lizard.h" + +#include +#include +#include +#include +#include +#include +#include + +struct lizard_buffer * +lizard_alloc(uns max_len) +{ + static byte *zero = "/dev/zero"; + int fd = open(zero, O_RDWR); + if (fd < 0) + die("open(%s): %m", zero); + struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer)); + buf->len = ALIGN(max_len + PAGE_SIZE, PAGE_SIZE); + buf->ptr = mmap(NULL, buf->len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (buf->ptr == MAP_FAILED) + die("mmap(%s): %m", zero); + return buf; +} + +void +lizard_free(struct lizard_buffer *buf) +{ + munmap(buf->ptr, buf->len); + xfree(buf); +} + +static jmp_buf safe_decompress_jump; +static void +sigsegv_handler(int UNUSED whatsit) +{ + log(L_ERROR, "SIGSEGV caught in lizard_decompress()"); + longjmp(safe_decompress_jump, 1); +} + +int +lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length) + /* Decompresses into buf->ptr and returns the length of the uncompressed + * file. If an error has occured, -1 is returned and errno is set. SIGSEGV + * is caught in the case of buffer-overflow. The function is not re-entrant + * because of a static longjmp handler. */ +{ + uns lock_offset = ALIGN(expected_length, PAGE_SIZE); + if (lock_offset + PAGE_SIZE > buf->len) + { + errno = EFBIG; + return -1; + } + mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_NONE); + volatile sighandler_t old_handler = signal(SIGSEGV, sigsegv_handler); + int len, err; + if (!setjmp(safe_decompress_jump)) + { + len = lizard_decompress(in, buf->ptr); + err = errno; + } + else + { + len = -1; + err = EFAULT; + } + signal(SIGSEGV, old_handler); + mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_READ | PROT_WRITE); + errno = err; + return len; +} -- 2.39.2