about summary refs log tree commit diff
path: root/locale/loadarchive.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-08-22 08:11:48 +0000
committerRoland McGrath <roland@gnu.org>2002-08-22 08:11:48 +0000
commit4e20f1e2150d0f57a4e04643bb1723607d14a234 (patch)
tree74de22bae022eae4f1649cd54e6ad25205c6e096 /locale/loadarchive.c
parent5015cde4c8f4d5b50c906967cdf88d8bff82dca1 (diff)
downloadglibc-4e20f1e2150d0f57a4e04643bb1723607d14a234.tar.gz
glibc-4e20f1e2150d0f57a4e04643bb1723607d14a234.tar.xz
glibc-4e20f1e2150d0f57a4e04643bb1723607d14a234.zip
* locale/loadarchive.c (_nl_load_locale_from_archive): Check max file
	position indicated by locrectab against file bounds before rounding to
	page size.  In mapping loop, always set TO before breaking out of
	contiguous range coalescing loop.

	* locale/loadarchive.c (_nl_load_locale_from_archive): Use MAP_PRIVATE
	(or MAP_COPY if available) instead of MAP_SHARED.
Diffstat (limited to 'locale/loadarchive.c')
-rw-r--r--locale/loadarchive.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/locale/loadarchive.c b/locale/loadarchive.c
index e32e8c7648..d25334a7fd 100644
--- a/locale/loadarchive.c
+++ b/locale/loadarchive.c
@@ -45,6 +45,19 @@ static const char archfname[] = LOCALEDIR "/locale-archive";
    cover the header plus the initial locale.  */
 #define ARCHIVE_MAPPING_WINDOW	(2 * 1024 * 1024)
 
+#ifndef MAP_COPY
+/* This is not quite as good as MAP_COPY since unexamined pages
+   can change out from under us and give us inconsistent data.
+   But we rely on the user not to diddle the system's live archive.
+   Even though we only ever use PROT_READ, using MAP_SHARED would
+   not give the system sufficient freedom to e.g. let the on disk
+   file go away because it doesn't know we won't call mprotect later.  */
+# define MAP_COPY MAP_PRIVATE
+#endif
+#ifndef MAP_FILE
+ /* Some systems do not have this flag; it is superfluous.  */
+# define MAP_FILE 0
+#endif
 
 /* Record of contiguous pages already mapped from the locale archive.  */
 struct archmapped
@@ -208,7 +221,7 @@ _nl_load_locale_from_archive (int category, const char **namep)
       mapsize = (sizeof (void *) > 4 ? archive_stat.st_size
 		 : MIN (archive_stat.st_size, ARCHIVE_MAPPING_WINDOW));
 
-      result = __mmap64 (NULL, mapsize, PROT_READ, MAP_SHARED, fd, 0);
+      result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
       if (result == MAP_FAILED)
 	goto close_and_out;
 
@@ -226,7 +239,8 @@ _nl_load_locale_from_archive (int category, const char **namep)
 	  /* Freakishly long header.  */
 	  /* XXX could use mremap when available */
 	  mapsize = (headsize + ps - 1) & ~(ps - 1);
-	  result = __mmap64 (NULL, mapsize, PROT_READ, MAP_SHARED, fd, 0);
+	  result = __mmap64 (NULL, mapsize, PROT_READ, MAP_FILE|MAP_COPY,
+			     fd, 0);
 	  if (result == MAP_FAILED)
 	    goto close_and_out;
 	}
@@ -357,20 +371,21 @@ _nl_load_locale_from_archive (int category, const char **namep)
 	  upper = cnt;
 	  do
 	    {
+	      to = ranges[upper].from + ranges[upper].len;
+	      if (to > archive_stat.st_size)
+		/* The archive locrectab contains bogus offsets.  */
+		return NULL;
+	      to = (to + ps - 1) & ~(ps - 1);
+
 	      /* If a range is already mmaped in, stop.	 */
 	      if (mapped != NULL && ranges[upper].from >= mapped->from)
 		break;
-	      to = ((ranges[upper].from + ranges[upper].len + ps - 1)
-		    & ~(ps - 1));
+
 	      ++upper;
 	    }
 	  /* Loop while still in contiguous pages. */
 	  while (upper < nranges && ranges[upper].from < to + ps);
 
-	  if (to > archive_stat.st_size)
-	    /* The archive locrectab contains bogus offsets.  */
-	    return NULL;
-
 	  /* Open the file if it hasn't happened yet.  */
 	  if (fd == -1)
 	    {
@@ -391,7 +406,8 @@ _nl_load_locale_from_archive (int category, const char **namep)
 	    }
 
 	  /* Map the range from the archive.  */
-	  addr = __mmap64 (NULL, to - from, PROT_READ, MAP_SHARED, fd, from);
+	  addr = __mmap64 (NULL, to - from, PROT_READ, MAP_FILE|MAP_COPY,
+			   fd, from);
 	  if (addr == MAP_FAILED)
 	    return NULL;