]> mj.ucw.cz Git - libucw.git/blob - lib/lizard-safe.c
fb45f8bf17f8a6d83b694485f8ed10dc80f009fd
[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   static byte *zero = "/dev/zero";
25   int fd = open(zero, O_RDWR);
26   if (fd < 0)
27     die("open(%s): %m", zero);
28   struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
29   buf->len = ALIGN(max_len + PAGE_SIZE, PAGE_SIZE);
30   buf->ptr = mmap(NULL, buf->len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
31   if (buf->ptr == MAP_FAILED)
32     die("mmap(%s): %m", zero);
33   return buf;
34 }
35
36 void
37 lizard_free(struct lizard_buffer *buf)
38 {
39   munmap(buf->ptr, buf->len);
40   xfree(buf);
41 }
42
43 static jmp_buf safe_decompress_jump;
44 static void
45 sigsegv_handler(int UNUSED whatsit)
46 {
47   log(L_ERROR, "SIGSEGV caught in lizard_decompress()");
48   longjmp(safe_decompress_jump, 1);
49 }
50
51 int
52 lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length)
53   /* Decompresses into buf->ptr and returns the length of the uncompressed
54    * file.  If an error has occured, -1 is returned and errno is set.  SIGSEGV
55    * is caught in the case of buffer-overflow.  The function is not re-entrant
56    * because of a static longjmp handler.  */
57 {
58   uns lock_offset = ALIGN(expected_length, PAGE_SIZE);
59   if (lock_offset + PAGE_SIZE > buf->len)
60   {
61     errno = EFBIG;
62     return -1;
63   }
64   mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_NONE);
65   volatile sighandler_t old_handler = signal(SIGSEGV, sigsegv_handler);
66   int len, err;
67   if (!setjmp(safe_decompress_jump))
68   {
69     len = lizard_decompress(in, buf->ptr);
70     err = errno;
71   }
72   else
73   {
74     len = -1;
75     err = EFAULT;
76   }
77   signal(SIGSEGV, old_handler);
78   mprotect(buf->ptr + lock_offset, PAGE_SIZE, PROT_READ | PROT_WRITE);
79   errno = err;
80   return len;
81 }