]> mj.ucw.cz Git - libucw.git/blob - lib/lizard-safe.c
MJ's suggestion:
[libucw.git] / lib / lizard-safe.c
1 /*
2  *      LiZaRd -- Fast compression method based on Lempel-Ziv 77
3  *
4  *      (c) 2004, Robert Spalek <robert@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "lib/lizard.h"
12
13 #include <stdlib.h>
14 #include <sys/mman.h>
15 #include <sys/user.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #include <setjmp.h>
19 #include <errno.h>
20
21 struct lizard_buffer *
22 lizard_alloc(uns max_len)
23 {
24   struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
25   buf->len = ALIGN(max_len + PAGE_SIZE, PAGE_SIZE);
26   buf->ptr = mmap(NULL, buf->len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
27   if (buf->ptr == MAP_FAILED)
28     die("mmap(anonymous): %m");
29   return buf;
30 }
31
32 void
33 lizard_free(struct lizard_buffer *buf)
34 {
35   munmap(buf->ptr, buf->len);
36   xfree(buf);
37 }
38
39 static jmp_buf safe_decompress_jump;
40 static void
41 sigsegv_handler(int UNUSED whatsit)
42 {
43   log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
44   longjmp(safe_decompress_jump, 1);
45 }
46
47 int
48 lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length)
49   /* Decompresses into buf->ptr and returns the length of the uncompressed
50    * file.  If an error has occured, -1 is returned and errno is set.  SIGSEGV
51    * is caught in the case of buffer-overflow.  The function is not re-entrant
52    * because of a static longjmp handler.  */
53 {
54   volatile uns lock_offset = ALIGN(expected_length, PAGE_SIZE);
55   if (lock_offset + PAGE_SIZE > buf->len)
56   {
57     errno = EFBIG;
58     return -1;
59   }
60   mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_NONE);
61   volatile sighandler_t old_handler = signal(SIGSEGV, sigsegv_handler);
62   int len, err;
63   if (!setjmp(safe_decompress_jump))
64   {
65     len = lizard_decompress(in, buf->ptr);
66     err = errno;
67   }
68   else
69   {
70     len = -1;
71     err = EFAULT;
72   }
73   signal(SIGSEGV, old_handler);
74   mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_READ | PROT_WRITE);
75   errno = err;
76   return len;
77 }