summaryrefslogtreecommitdiff
path: root/catgets
diff options
context:
space:
mode:
Diffstat (limited to 'catgets')
-rw-r--r--catgets/open_catalog.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/catgets/open_catalog.c b/catgets/open_catalog.c
index 9d54124cd0..deaa8718dd 100644
--- a/catgets/open_catalog.c
+++ b/catgets/open_catalog.c
@@ -19,6 +19,7 @@
#include <byteswap.h>
#include <endian.h>
+#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
@@ -38,6 +39,10 @@ __open_catalog (__nl_catd catalog)
int fd = -1;
struct stat st;
int swapping;
+ size_t cnt;
+ size_t max_offset;
+ size_t tab_size;
+ const char *lastp;
/* Make sure we are alone. */
__libc_lock_lock (catalog->lock);
@@ -175,11 +180,19 @@ __open_catalog (__nl_catd catalog)
}
/* Avoid dealing with directories and block devices */
- if (fd < 0 || __fstat (fd, &st) < 0 || !S_ISREG (st.st_mode))
+ if (fd < 0 || __fstat (fd, &st) < 0)
{
catalog->status = nonexisting;
goto unlock_return;
}
+ if (!S_ISREG (st.st_mode) || st.st_size < sizeof (struct catalog_obj))
+ {
+ /* `errno' is not set correctly but the file is not usable.
+ Use an reasonable error value. */
+ __set_errno (EINVAL);
+ catalog->status = nonexisting;
+ goto unlock_return;
+ }
#ifndef MAP_COPY
/* Linux seems to lack read-only copy-on-write. */
@@ -242,6 +255,7 @@ __open_catalog (__nl_catd catalog)
swapping = 1;
else
{
+ invalid_file:
/* Invalid file. Free the resources and mark catalog as not
usable. */
if (catalog->status == mmapped)
@@ -276,6 +290,29 @@ __open_catalog (__nl_catd catalog)
(const char *) &catalog->file_ptr->name_ptr[catalog->plane_size
* catalog->plane_depth * 3 * 2];
+ /* Determine the largest string offset mentioned in the table. */
+ max_offset = 0;
+ tab_size = 3 * catalog->plane_size * catalog->plane_depth;
+ for (cnt = 2; cnt < tab_size; cnt += 3)
+ if (catalog->name_ptr[cnt] > max_offset)
+ max_offset = catalog->name_ptr[cnt];
+
+ /* Now we can check whether the file is large enough to contain the
+ tables it says it contains. */
+ if (st.st_size <= (sizeof (struct catalog_obj) + 2 * tab_size + max_offset))
+ /* The last string is not contained in the file. */
+ goto invalid_file;
+
+ lastp = catalog->strings + max_offset;
+ max_offset = (st.st_size
+ - sizeof (struct catalog_obj) + 2 * tab_size + max_offset);
+ while (*lastp != '\0')
+ {
+ if (--max_offset == 0)
+ goto invalid_file;
+ ++lastp;
+ }
+
/* Release the lock again. */
unlock_return:
if (fd != -1)