about summary refs log tree commit diff
path: root/locale/loadarchive.c
diff options
context:
space:
mode:
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;