]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Catch incorrect string indeces and empty input file.
authorUlrich Drepper <drepper@redhat.com>
Tue, 21 Jul 1998 12:16:02 +0000 (12:16 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 21 Jul 1998 12:16:02 +0000 (12:16 +0000)
catgets/open_catalog.c

index c3f10ffe5376dadd84c09c30464d3c78094bdcdf..92f8f2e3406d9377cc2ca2e821db04895d72385f 100644 (file)
@@ -18,6 +18,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #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 with_path)
   int fd = -1;
   struct stat st;
   int swapping;
+  size_t cnt;
+  size_t max_offset;
+  size_t tab_size;
+  const char *lastp;
 
   if (strchr (catalog->cat_name, '/') != NULL || !with_path)
     fd = open (catalog->cat_name, O_RDONLY);
@@ -161,13 +166,21 @@ __open_catalog (__nl_catd catalog, int with_path)
        }
     }
 
-  if (fd < 0 || __fstat (fd, &st) < 0 || !S_ISREG (st.st_mode))
+  if (fd < 0 || __fstat (fd, &st) < 0)
     {
       if (fd != -1)
        __close (fd);
       catalog->status = nonexisting;
       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;
+      return;
+    }
 
 #ifndef MAP_COPY
     /* Linux seems to lack read-only copy-on-write.  */
@@ -231,7 +244,8 @@ __open_catalog (__nl_catd catalog, int with_path)
     swapping = 1;
   else
     {
-      /* Illegal file.  Free he resources and mark catalog as not
+    invalid_file:
+      /* Invalid file.  Free he resources and mark catalog as not
         usable.  */
       if (catalog->status == mmapped)
        __munmap ((void *) catalog->file_ptr, catalog->file_size);
@@ -264,4 +278,27 @@ __open_catalog (__nl_catd catalog, int with_path)
   catalog->strings =
     (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;
+    }
 }