#include <setjmp.h>
#include <errno.h>
-static void
-lizard_alloc_internal(struct lizard_buffer *buf, uns max_len)
-{
- if (!max_len)
- {
- buf->len = 0;
- buf->start = NULL;
- return;
- }
- buf->len = ALIGN(max_len + 3, PAGE_SIZE); // +3 due to the unaligned access
- buf->start = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (buf->start == MAP_FAILED)
- die("mmap(anonymous): %m");
- if (mprotect(buf->start + buf->len, PAGE_SIZE, PROT_NONE) < 0)
- die("mprotect: %m");
-}
+struct lizard_buffer {
+ uns len;
+ void *ptr;
+ struct sigaction *old_sigsegv_handler;
+};
struct lizard_buffer *
-lizard_alloc(uns max_len)
+lizard_alloc(void)
{
struct lizard_buffer *buf = xmalloc(sizeof(struct lizard_buffer));
- lizard_alloc_internal(buf, max_len);
+ buf->len = 0;
+ buf->ptr = NULL;
buf->old_sigsegv_handler = xmalloc(sizeof(struct sigaction));
handle_signal(SIGSEGV, buf->old_sigsegv_handler);
return buf;
void
lizard_free(struct lizard_buffer *buf)
{
- if (buf->start)
- munmap(buf->start, buf->len + PAGE_SIZE);
+ if (buf->ptr)
+ munmap(buf->ptr, buf->len + PAGE_SIZE);
unhandle_signal(SIGSEGV, buf->old_sigsegv_handler);
xfree(buf->old_sigsegv_handler);
xfree(buf);
}
-void
+static void
lizard_realloc(struct lizard_buffer *buf, uns max_len)
+ /* max_len needs to be aligned to PAGE_SIZE */
{
- max_len += 3;
if (max_len <= buf->len)
return;
- if (max_len < 2*buf->len) // to ensure amortized logarithmic complexity
+ if (max_len < 2*buf->len) // to ensure logarithmic cost
max_len = 2*buf->len;
- if (buf->start)
- munmap(buf->start - 3, buf->len + PAGE_SIZE);
- lizard_alloc_internal(buf, max_len);
+
+ if (buf->ptr)
+ munmap(buf->ptr, buf->len + PAGE_SIZE);
+ buf->len = max_len;
+ buf->ptr = mmap(NULL, buf->len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | 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("mprotect: %m");
}
static jmp_buf safe_decompress_jump;
}
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. */
+lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length, byte **ptr)
+ /* 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
if (lock_offset > buf->len)
- {
- errno = EFBIG;
- return -1;
- }
+ lizard_realloc(buf, lock_offset);
volatile sh_sighandler_t old_handler = signal_handler[SIGSEGV];
signal_handler[SIGSEGV] = sigsegv_handler;
int len;
if (!setjmp(safe_decompress_jump))
{
- buf->ptr = buf->start + buf->len - lock_offset;
- len = lizard_decompress(in, buf->ptr);
+ *ptr = buf->ptr + buf->len - lock_offset;
+ len = lizard_decompress(in, *ptr);
}
else
{
- buf->ptr = NULL;
+ *ptr = NULL;
len = -1;
errno = EFAULT;
}
* The multiplicative constant comes from 19-byte incompressible string
* followed by a 3-sequence that can be compressed into 2-byte link. This
* breaks the copy-mode and it needs to be restarted with a new header. The
- * total length is 2(header) + 2(link) + 19(string) = 23.
+ * total length is 2(header) + 19(string) + 2(link) = 23.
*/
/* lizard.c */
int lizard_decompress(byte *in, byte *out);
/* lizard-safe.c */
-struct sigaction;
-struct lizard_buffer {
- uns len;
- void *start, *ptr;
- struct sigaction *old_sigsegv_handler;
-};
+struct lizard_buffer;
-struct lizard_buffer *lizard_alloc(uns max_len);
+struct lizard_buffer *lizard_alloc(void);
void lizard_free(struct lizard_buffer *buf);
-void lizard_realloc(struct lizard_buffer *buf, uns max_len);
-int lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length);
+int lizard_decompress_safe(byte *in, struct lizard_buffer *buf, uns expected_length, byte **ptr);