[BZ #10283] localedef: align fixed maps to SHMLBA

Many Linux arches require fixed mmaps to be aligned higher than pagesize,
so use the SHMLBA define as it represents this quantity exactly.

This fixes spurious errors seen on those arches like:
cannot map archive header: Invalid argument

URL: http://sourceware.org/bugzilla/show_bug.cgi?id=10283
Reported-by: CHIKAMA Masaki <masaki.chikama@gmail.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
Mike Frysinger 2013-05-23 12:42:28 -04:00
parent d605071ebf
commit 17db6e8d6b
5 changed files with 113 additions and 29 deletions

View File

@ -1,3 +1,25 @@
2013-06-24 Mike Frysinger <vapier@gentoo.org>
[BZ #10283]
* NEWS: Note fixing of BZ #10283.
* locale/locarchive.h (struct locarhandle): Add mmap_base and mmap_len.
* locale/programs/locarchive.c: Include libc-mmap.h.
(prepare_address_space): Take two new outputs (the mmap base and len).
Align p to MAP_FIXED_ALIGNMENT. Set mmap base and len to the right
values.
(create_archive): Declare new mmap base and len values for
prepare_address_space, and store the result in ah.
(file_data_available_p): Replace pagesz with MAP_FIXED_ALIGNMENT.
(enlarge_archive): If ah->mmap_base is not NULL, use that and
ah->mmap_len to unmap rather than ah->addr and ah->reserved.
Declare new mmap base and len values for
prepare_address_space, and store the result in new_ah.
(open_archive): Declare new mmap base and len values for
prepare_address_space, and store the result in ah.
(close_archive): If ah->mmap_base is not NULL, use that and
ah->mmap_len to unmap rather than ah->addr and ah->reserved.
* sysdeps/generic/libc-mmap.h: New file.
2013-06-24 Mike Frysinger <vapier@gentoo.org>
* include/libc-internal.h (ALIGN_DOWN): New helper macro.

26
NEWS
View File

@ -9,19 +9,19 @@ Version 2.18
* The following bugs are resolved with this release:
2546, 2560, 5159, 6809, 7006, 10060, 10062, 10357, 10686, 11120, 11561,
12310, 12387, 12515, 12723, 13550, 13889, 13951, 13988, 14142, 14176,
14200, 14256, 14280, 14293, 14317, 14327, 14478, 14496, 14582, 14686,
14812, 14888, 14894, 14907, 14908, 14909, 14920, 14952, 14964, 14981,
14982, 14985, 14991, 14994, 14996, 15000, 15003, 15006, 15007, 15014,
15020, 15023, 15036, 15054, 15055, 15062, 15078, 15084, 15085, 15086,
15100, 15160, 15214, 15221, 15232, 15234, 15283, 15285, 15287, 15304,
15305, 15307, 15309, 15327, 15330, 15335, 15336, 15337, 15339, 15342,
15346, 15359, 15361, 15366, 15380, 15381, 15394, 15395, 15405, 15406,
15409, 15416, 15418, 15419, 15423, 15424, 15426, 15429, 15431, 15432,
15441, 15442, 15448, 15465, 15480, 15485, 15488, 15490, 15492, 15493,
15497, 15506, 15529, 15536, 15553, 15577, 15583, 15618, 15627, 15631,
15654, 15655, 15667.
2546, 2560, 5159, 6809, 7006, 10060, 10062, 10283, 10357, 10686, 11120,
11561, 12310, 12387, 12515, 12723, 13550, 13889, 13951, 13988, 14142,
14176, 14200, 14256, 14280, 14293, 14317, 14327, 14478, 14496, 14582,
14686, 14812, 14888, 14894, 14907, 14908, 14909, 14920, 14952, 14964,
14981, 14982, 14985, 14991, 14994, 14996, 15000, 15003, 15006, 15007,
15014, 15020, 15023, 15036, 15054, 15055, 15062, 15078, 15084, 15085,
15086, 15100, 15160, 15214, 15221, 15232, 15234, 15283, 15285, 15287,
15304, 15305, 15307, 15309, 15327, 15330, 15335, 15336, 15337, 15339,
15342, 15346, 15359, 15361, 15366, 15380, 15381, 15394, 15395, 15405,
15406, 15409, 15416, 15418, 15419, 15423, 15424, 15426, 15429, 15431,
15432, 15441, 15442, 15448, 15465, 15480, 15485, 15488, 15490, 15492,
15493, 15497, 15506, 15529, 15536, 15553, 15577, 15583, 15618, 15627,
15631, 15654, 15655, 15667.
* CVE-2013-0242 Buffer overrun in regexp matcher has been fixed (Bugzilla
#15078).

View File

@ -84,6 +84,13 @@ struct locarhandle
void *addr;
size_t mmaped;
size_t reserved;
/* If this mmap required adjustment (such as re-aligning), then this is the
real address that was returned from mmap and thus should be passed to the
munmap call. The addr field above is the first usable address. */
void *mmap_base;
/* Same as above for mmap_base vs addr, but this is the real length of the
map rather than the usable (which is what reserved represents). */
size_t mmap_len;
};

View File

@ -37,8 +37,10 @@
#include <stdint.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <libc-mmap.h>
#include "../../crypt/md5.h"
#include "../localeinfo.h"
#include "../locarchive.h"
@ -79,21 +81,29 @@ static const char *locnames[] =
mapping affects the address selection. So do this mapping from the
actual file, even though it's only a dummy to reserve address space. */
static void *
prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags)
prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags,
void **mmap_base, size_t *mmap_len)
{
if (total < RESERVE_MMAP_SIZE)
{
void *p = mmap64 (NULL, RESERVE_MMAP_SIZE, PROT_NONE, MAP_SHARED, fd, 0);
if (p != MAP_FAILED)
{
*reserved = RESERVE_MMAP_SIZE;
void *aligned_p = PTR_ALIGN_UP (p, MAP_FIXED_ALIGNMENT);
size_t align_adjust = aligned_p - p;
*mmap_base = p;
*mmap_len = RESERVE_MMAP_SIZE;
assert (align_adjust < RESERVE_MMAP_SIZE);
*reserved = RESERVE_MMAP_SIZE - align_adjust;
*xflags = MAP_FIXED;
return p;
return aligned_p;
}
}
*reserved = total;
*xflags = 0;
*mmap_base = NULL;
*mmap_len = 0;
return NULL;
}
@ -151,9 +161,11 @@ create_archive (const char *archivefname, struct locarhandle *ah)
error (EXIT_FAILURE, errval, _("cannot resize archive file"));
}
size_t reserved;
size_t reserved, mmap_len;
int xflags;
void *p = prepare_address_space (fd, total, &reserved, &xflags);
void *mmap_base;
void *p = prepare_address_space (fd, total, &reserved, &xflags, &mmap_base,
&mmap_len);
/* Map the header and all the administration data structures. */
p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
@ -199,6 +211,8 @@ create_archive (const char *archivefname, struct locarhandle *ah)
}
ah->fd = fd;
ah->mmap_base = mmap_base;
ah->mmap_len = mmap_len;
ah->addr = p;
ah->mmaped = total;
ah->reserved = reserved;
@ -271,8 +285,7 @@ file_data_available_p (struct locarhandle *ah, uint32_t offset, uint32_t size)
if (st.st_size > ah->reserved)
return false;
const size_t pagesz = getpagesize ();
size_t start = ah->mmaped & ~(pagesz - 1);
size_t start = ALIGN_DOWN (ah->mmaped, MAP_FIXED_ALIGNMENT);
void *p = mmap64 (ah->addr + start, st.st_size - start,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
ah->fd, start);
@ -332,10 +345,15 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
MAP_SHARED | MAP_FIXED, ah->fd, 0);
else
{
if (ah->mmap_base)
munmap (ah->mmap_base, ah->mmap_len);
else
munmap (ah->addr, ah->reserved);
ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, ah->fd, 0);
ah->reserved = st.st_size;
ah->mmap_base = NULL;
ah->mmap_len = 0;
head = ah->addr;
}
if (ah->addr == MAP_FAILED)
@ -401,9 +419,11 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
error (EXIT_FAILURE, errval, _("cannot resize archive file"));
}
size_t reserved;
size_t reserved, mmap_len;
int xflags;
void *p = prepare_address_space (fd, total, &reserved, &xflags);
void *mmap_base;
void *p = prepare_address_space (fd, total, &reserved, &xflags, &mmap_base,
&mmap_len);
/* Map the header and all the administration data structures. */
p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
@ -423,6 +443,8 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
}
new_ah.mmaped = total;
new_ah.mmap_base = mmap_base;
new_ah.mmap_len = mmap_len;
new_ah.addr = p;
new_ah.fd = fd;
new_ah.reserved = reserved;
@ -606,9 +628,11 @@ open_archive (struct locarhandle *ah, bool readonly)
ah->fd = fd;
ah->mmaped = st.st_size;
size_t reserved;
size_t reserved, mmap_len;
int xflags;
void *p = prepare_address_space (fd, st.st_size, &reserved, &xflags);
void *mmap_base;
void *p = prepare_address_space (fd, st.st_size, &reserved, &xflags,
&mmap_base, &mmap_len);
/* Map the entire file. We might need to compare the category data
in the file with the newly added data. */
@ -620,6 +644,8 @@ open_archive (struct locarhandle *ah, bool readonly)
error (EXIT_FAILURE, errno, _("cannot map archive header"));
}
ah->reserved = reserved;
ah->mmap_base = mmap_base;
ah->mmap_len = mmap_len;
}
@ -628,6 +654,9 @@ close_archive (struct locarhandle *ah)
{
if (ah->fd != -1)
{
if (ah->mmap_base)
munmap (ah->mmap_base, ah->mmap_len);
else
munmap (ah->addr, ah->reserved);
close (ah->fd);
}

View File

@ -0,0 +1,26 @@
/* Internal logic for dealing with mmap quirks.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _LIBC_MMAP_H
#define _LIBC_MMAP_H 1
/* Using MAP_FIXED with mmap sometimes requires larger alignment. */
#include <sys/shm.h>
#define MAP_FIXED_ALIGNMENT SHMLBA
#endif