Commit 6ec01d9c authored by Tobias Stoeckmann's avatar Tobias Stoeckmann
Browse files

Verify that opened message catalog is valid, i.e. avoid integer overflows

and out of boundary accesses.

with input by miod, ok stsp
parent e6e8c193
/* $OpenBSD: catopen.c,v 1.17 2015/09/05 11:25:30 guenther Exp $ */
/* $OpenBSD: catopen.c,v 1.18 2015/10/23 18:49:07 tobias Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
......@@ -30,20 +30,24 @@
#define _NLS_PRIVATE
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <nl_types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
#define NLS_DEFAULT_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%l.%c/%N.cat:/usr/share/nls/%l/%N.cat"
#define NLS_DEFAULT_LANG "C"
static nl_catd load_msgcat(const char *);
static nl_catd load_msgcat(const char *);
static int verify_msgcat(nl_catd);
nl_catd
catopen(const char *name, int oflag)
......@@ -165,6 +169,8 @@ load_msgcat(const char *path)
void *data;
int fd;
catd = NULL;
if ((fd = open(path, O_RDONLY|O_CLOEXEC)) == -1)
return (nl_catd) -1;
......@@ -173,24 +179,106 @@ load_msgcat(const char *path)
return (nl_catd) -1;
}
data = mmap(0, (size_t) st.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0);
close (fd);
if (data == MAP_FAILED) {
if (st.st_size > INT_MAX || st.st_size < sizeof (struct _nls_cat_hdr)) {
errno = EINVAL;
close (fd);
return (nl_catd) -1;
}
if (ntohl(((struct _nls_cat_hdr *) data)->__magic) != _NLS_MAGIC) {
munmap(data, (size_t) st.st_size);
return (nl_catd) -1;
}
data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0);
close (fd);
if ((catd = malloc(sizeof (*catd))) == 0) {
munmap(data, (size_t) st.st_size);
if (data == MAP_FAILED)
return (nl_catd) -1;
}
if (ntohl(((struct _nls_cat_hdr *) data)->__magic) != _NLS_MAGIC)
goto invalid;
if ((catd = malloc(sizeof (*catd))) == 0)
goto invalid;
catd->__data = data;
catd->__size = st.st_size;
if (verify_msgcat(catd))
goto invalid;
return catd;
invalid:
free(catd);
munmap(data, (size_t) st.st_size);
errno = EINVAL;
return (nl_catd) -1;
}
static int
verify_msgcat(nl_catd catd)
{
struct _nls_cat_hdr *cat;
struct _nls_set_hdr *set;
struct _nls_msg_hdr *msg;
size_t remain;
int hdr_offset, i, index, j, msgs, nmsgs, nsets, off, txt_offset;
remain = catd->__size;
cat = (struct _nls_cat_hdr *) catd->__data;
hdr_offset = ntohl(cat->__msg_hdr_offset);
nsets = ntohl(cat->__nsets);
txt_offset = ntohl(cat->__msg_txt_offset);
/* catalog must contain at least one set and no negative offsets */
if (nsets < 1 || hdr_offset < 0 || txt_offset < 0)
return (1);
remain -= sizeof (*cat);
/* check if offsets or set size overflow */
if (remain <= hdr_offset || remain <= ntohl(cat->__msg_txt_offset) ||
remain / sizeof (*set) < nsets)
return (1);
set = (struct _nls_set_hdr *) ((char *) catd->__data + sizeof (*cat));
/* make sure that msg has space for at least one index */
if (remain - hdr_offset < sizeof(*msg))
return (1);
msg = (struct _nls_msg_hdr *) ((char *) catd->__data + sizeof (*cat)
+ hdr_offset);
/* validate and retrieve largest string offset from sets */
off = 0;
for (i = 0; i < nsets; i++) {
index = ntohl(set[i].__index);
nmsgs = ntohl(set[i].__nmsgs);
/* set must contain at least one message */
if (index < 0 || nmsgs < 1)
return (1);
if (INT_MAX - nmsgs < index)
return (1);
msgs = index + nmsgs;
/* avoid msg index overflow */
if ((remain - hdr_offset) / sizeof(*msg) < msgs)
return (1);
/* retrieve largest string offset */
for (j = index; j < nmsgs; j++) {
if (ntohl(msg[j].__offset) < 0)
return (1);
off = MAXIMUM(off, ntohl(msg[j].__offset));
}
}
/* check if largest string offset is nul-terminated */
if (remain - txt_offset < off ||
memchr((char *) catd->__data + sizeof(*cat) + txt_offset + off,
'\0', remain - txt_offset - off) == NULL)
return (1);
return (0);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment