* elf/dl-load.c (_dl_map_object_from_fd): Split out ELF file
	verification in open_verify.
	(open_verify): New function.  Called instead of open.  Ignores valid
	files for other architectures.
	(open_path): Call open_verify instead of open.
	(_dl_map_object): Likewise.
	Somewhat based on a patch by Don Dugger <n0ano@valinux.com>.

	* io/pwd.c (main): The output was missing a newline.
This commit is contained in:
Ulrich Drepper 2000-10-21 17:08:18 +00:00
parent d1990c5562
commit a35e137a99
2 changed files with 166 additions and 96 deletions

View File

@ -1,5 +1,15 @@
2000-10-21 Ulrich Drepper <drepper@redhat.com>
* elf/dl-load.c (_dl_map_object_from_fd): Split out ELF file
verification in open_verify.
(open_verify): New function. Called instead of open. Ignores valid
files for other architectures.
(open_path): Call open_verify instead of open.
(_dl_map_object): Likewise.
Somewhat based on a patch by Don Dugger <n0ano@valinux.com>.
* io/pwd.c (main): The output was missing a newline.
* posix/fnmatch_loop.c: Make FNM_LEADING_DIR behave as GNU tar
expects it. Patch by Colin Watson <riva.ucam.org>.
* posix/tst-fnmatch.input: Add test cases for FNM_LEADING_DIR.

View File

@ -92,6 +92,24 @@ ELF_PREFERRED_ADDRESS_DATA;
# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
#endif
/* Type for the buffer we put the ELF header and hopefully the program
header. This buffer does not really have to be too large. In most
cases the program header follows the ELF header directly. If this
is not the case all bets are off and we can make the header arbitrarily
large and still won't get it read. This means the only question is
how large are the ELF and program header combined. The ELF header
in 64-bit files is 56 bytes long. Each program header entry is again
56 bytes long. I.e., even with a file which has 17 program header
entries we only have to read 1kB. And 17 program header entries is
plenty, normal files have < 10. If this heuristic should really fail
for some file the code in `_dl_map_object_from_fd' knows how to
recover. */
struct filebuf
{
ssize_t len;
char buf[1024];
};
size_t _dl_pagesize;
extern const char *_dl_platform;
@ -724,29 +742,10 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
static
#endif
struct link_map *
_dl_map_object_from_fd (const char *name, int fd, char *realname,
struct link_map *loader, int l_type, int mode)
_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
char *realname, struct link_map *loader, int l_type,
int mode)
{
/* This is the expected ELF header. */
#define ELF32_CLASS ELFCLASS32
#define ELF64_CLASS ELFCLASS64
#ifndef VALID_ELF_HEADER
# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0)
# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV)
# define VALID_ELF_ABIVERSION(ver) (ver == 0)
#endif
static const unsigned char expected[EI_PAD] =
{
[EI_MAG0] = ELFMAG0,
[EI_MAG1] = ELFMAG1,
[EI_MAG2] = ELFMAG2,
[EI_MAG3] = ELFMAG3,
[EI_CLASS] = ELFW(CLASS),
[EI_DATA] = byteorder,
[EI_VERSION] = EV_CURRENT,
[EI_OSABI] = ELFOSABI_SYSV,
[EI_ABIVERSION] = 0
};
struct link_map *l = NULL;
inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len,
@ -765,8 +764,6 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
const ElfW(Phdr) *ph;
size_t maplength;
int type;
char *readbuf;
ssize_t readlength;
struct stat64 st;
/* Get file information. */
@ -804,64 +801,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
if (__builtin_expect (_dl_debug_files, 0))
_dl_debug_message (1, "file=", name, "; generating link map\n", NULL);
/* Read the header directly. */
readbuf = alloca (_dl_pagesize);
readlength = __libc_read (fd, readbuf, _dl_pagesize);
if (readlength < (ssize_t) sizeof (*header))
LOSE (errno, N_("cannot read file data"));
header = (void *) readbuf;
/* Check the header for basic validity. */
if (__builtin_expect (!VALID_ELF_HEADER (header->e_ident, expected, EI_PAD),
0))
{
/* Something is wrong. */
if (*(Elf32_Word *) &header->e_ident !=
#if BYTE_ORDER == LITTLE_ENDIAN
((ELFMAG0 << (EI_MAG0 * 8)) |
(ELFMAG1 << (EI_MAG1 * 8)) |
(ELFMAG2 << (EI_MAG2 * 8)) |
(ELFMAG3 << (EI_MAG3 * 8)))
#else
((ELFMAG0 << (EI_MAG3 * 8)) |
(ELFMAG1 << (EI_MAG2 * 8)) |
(ELFMAG2 << (EI_MAG1 * 8)) |
(ELFMAG3 << (EI_MAG0 * 8)))
#endif
)
LOSE (0, N_("invalid ELF header"));
if (header->e_ident[EI_CLASS] != ELFW(CLASS))
{
if (__ELF_NATIVE_CLASS == 32)
LOSE (0, N_("ELF file class not 32-bit"));
else
LOSE (0, N_("ELF file class not 64-bit"));
}
if (header->e_ident[EI_DATA] != byteorder)
{
if (BYTE_ORDER == BIG_ENDIAN)
LOSE (0, "ELF file data encoding not big-endian");
else
LOSE (0, "ELF file data encoding not little-endian");
}
if (header->e_ident[EI_VERSION] != EV_CURRENT)
LOSE (0, N_("ELF file version ident does not match current one"));
/* XXX We should be able so set system specific versions which are
allowed here. */
if (!VALID_ELF_OSABI (header->e_ident[EI_OSABI]))
LOSE (0, N_("ELF file OS ABI invalid."));
if (!VALID_ELF_ABIVERSION (header->e_ident[EI_ABIVERSION]))
LOSE (0, N_("ELF file ABI version invalid."));
LOSE (0, N_("internal error"));
}
if (__builtin_expect (header->e_version, EV_CURRENT) != EV_CURRENT)
LOSE (0, N_("ELF file version does not match current one"));
if (! __builtin_expect (elf_machine_matches_host (header), 1))
LOSE (0, N_("ELF file machine architecture does not match"));
if (__builtin_expect (header->e_phentsize, sizeof (ElfW(Phdr)))
!= sizeof (ElfW(Phdr)))
LOSE (0, N_("ELF file's phentsize not the expected size"));
/* This is the ELF header. We read it in `open_verify'. */
header = (void *) fbp->buf;
#ifndef MAP_ANON
# define MAP_ANON 0
@ -889,8 +830,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
l->l_phnum = header->e_phnum;
maplength = header->e_phnum * sizeof (ElfW(Phdr));
if (header->e_phoff + maplength <= readlength)
phdr = (void *) (readbuf + header->e_phoff);
if (header->e_phoff + maplength <= fbp->len)
phdr = (void *) (fbp->buf + header->e_phoff);
else
{
phdr = alloca (maplength);
@ -1254,6 +1195,123 @@ print_search_path (struct r_search_path_elem **list,
_dl_debug_message (0, "\t\t(", what, ")\n", NULL);
}
/* Open a file and verify it is an ELF file for this architecture. We
ignore only ELF files for other architectures. Non-ELF files and
ELF files with different header information cause fatal errors since
this could mean there is something wrong in the installation and the
user might want to know about this. */
static int
open_verify (const char *name, struct filebuf *fbp)
{
/* This is the expected ELF header. */
#define ELF32_CLASS ELFCLASS32
#define ELF64_CLASS ELFCLASS64
#ifndef VALID_ELF_HEADER
# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0)
# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV)
# define VALID_ELF_ABIVERSION(ver) (ver == 0)
#endif
static const unsigned char expected[EI_PAD] =
{
[EI_MAG0] = ELFMAG0,
[EI_MAG1] = ELFMAG1,
[EI_MAG2] = ELFMAG2,
[EI_MAG3] = ELFMAG3,
[EI_CLASS] = ELFW(CLASS),
[EI_DATA] = byteorder,
[EI_VERSION] = EV_CURRENT,
[EI_OSABI] = ELFOSABI_SYSV,
[EI_ABIVERSION] = 0
};
int fd;
/* Open the file. We always open files read-only. */
fd = __open (name, O_RDONLY);
if (fd != -1)
{
ElfW(Ehdr) *ehdr;
/* We successfully openened the file. Now verify it is a file
we can use. */
__set_errno (0);
fbp->len = __libc_read (fd, fbp->buf, sizeof (fbp->buf));
/* This is where the ELF header is loaded. */
assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
ehdr = (ElfW(Ehdr) *) fbp->buf;
/* Now run the tests. */
if (__builtin_expect (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)), 0))
lose (errno, fd, name, NULL, NULL,
errno == 0 ? N_("file too short") : N_("cannot read file data"));
/* See whether the ELF header is what we expect. */
if (__builtin_expect (! VALID_ELF_HEADER (ehdr->e_ident, expected,
EI_PAD), 0))
{
/* Something is wrong. */
if (*(Elf32_Word *) &ehdr->e_ident !=
#if BYTE_ORDER == LITTLE_ENDIAN
((ELFMAG0 << (EI_MAG0 * 8)) |
(ELFMAG1 << (EI_MAG1 * 8)) |
(ELFMAG2 << (EI_MAG2 * 8)) |
(ELFMAG3 << (EI_MAG3 * 8)))
#else
((ELFMAG0 << (EI_MAG3 * 8)) |
(ELFMAG1 << (EI_MAG2 * 8)) |
(ELFMAG2 << (EI_MAG1 * 8)) |
(ELFMAG3 << (EI_MAG0 * 8)))
#endif
)
lose (0, fd, name, NULL, NULL, N_("invalid ELF header"));
if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS))
/* This is not a fatal error. On architectures where
32-bit and 64-bit binaries can be run this might
happen. */
goto close_and_out;
if (ehdr->e_ident[EI_DATA] != byteorder)
{
if (BYTE_ORDER == BIG_ENDIAN)
lose (0, fd, name, NULL, NULL,
"ELF file data encoding not big-endian");
else
lose (0, fd, name, NULL, NULL,
"ELF file data encoding not little-endian");
}
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
lose (0, fd, name, NULL, NULL,
N_("ELF file version ident does not match current one"));
/* XXX We should be able so set system specific versions which are
allowed here. */
if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI]))
lose (0, fd, name, NULL, NULL, N_("ELF file OS ABI invalid."));
if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_ABIVERSION]))
lose (0, fd, name, NULL, NULL,
N_("ELF file ABI version invalid."));
lose (0, fd, name, NULL, NULL, N_("internal error"));
}
if (__builtin_expect (ehdr->e_version, EV_CURRENT) != EV_CURRENT)
lose (0, fd, name, NULL, NULL,
N_("ELF file version does not match current one"));
if (! __builtin_expect (elf_machine_matches_host (ehdr), 1))
{
close_and_out:
__close (fd);
__set_errno (ENOENT);
fd = -1;
}
else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr)))
!= sizeof (ElfW(Phdr)))
lose (0, fd, name, NULL, NULL,
N_("ELF file's phentsize not the expected size"));
}
return fd;
}
/* Try to open NAME in one of the directories in *DIRSP.
Return the fd, or -1. If successful, fill in *REALNAME
with the malloc'd full directory name. If it turns out
@ -1263,7 +1321,8 @@ print_search_path (struct r_search_path_elem **list,
static int
open_path (const char *name, size_t namelen, int preloaded,
struct r_search_path_struct *sps, char **realname)
struct r_search_path_struct *sps, char **realname,
struct filebuf *fbp)
{
struct r_search_path_elem **dirs = sps->dirs;
char *buf;
@ -1305,7 +1364,7 @@ open_path (const char *name, size_t namelen, int preloaded,
if (__builtin_expect (_dl_debug_libs, 0))
_dl_debug_message (1, " trying file=", buf, "\n", NULL);
fd = __open (buf, O_RDONLY);
fd = open_verify (buf, fbp);
if (this_dir->status[cnt] == unknown)
{
if (fd != -1)
@ -1398,6 +1457,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
char *realname;
char *name_copy;
struct link_map *l;
struct filebuf fb;
/* Look for this name among those already loaded. */
for (l = _dl_loaded; l; l = l->l_next)
@ -1475,12 +1535,12 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (l->l_rpath_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded,
&l->l_rpath_dirs, &realname);
&l->l_rpath_dirs, &realname, &fb);
}
}
else if (l->l_rpath_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
&realname);
&realname, &fb);
}
/* If dynamically linked, try the DT_RPATH of the executable
@ -1489,13 +1549,13 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (fd == -1 && l && l->l_type != lt_loaded && l != loader
&& l->l_rpath_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
&realname);
&realname, &fb);
}
/* Try the LD_LIBRARY_PATH environment variable. */
if (fd == -1 && env_path_list.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded, &env_path_list,
&realname);
&realname, &fb);
/* Look at the RUNPATH informaiton for this binary. */
if (loader != NULL && loader->l_runpath_dirs.dirs != (void *) -1)
@ -1515,12 +1575,12 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (loader->l_runpath_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded,
&loader->l_runpath_dirs, &realname);
&loader->l_runpath_dirs, &realname, &fb);
}
}
else if (loader->l_runpath_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded,
&loader->l_runpath_dirs, &realname);
&loader->l_runpath_dirs, &realname, &fb);
}
if (fd == -1)
@ -1562,7 +1622,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
if (cached)
{
fd = __open (cached, O_RDONLY);
fd = open_verify (cached, &fb);
if (fd != -1)
{
realname = local_strdup (cached);
@ -1582,7 +1642,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
__builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
&& rtld_search_dirs.dirs != (void *) -1)
fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
&realname);
&realname, &fb);
/* Add another newline when we a tracing the library loading. */
if (__builtin_expect (_dl_debug_libs, 0))
@ -1598,7 +1658,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
fd = -1;
else
{
fd = __open (realname, O_RDONLY);
fd = open_verify (realname, &fb);
if (fd == -1)
free (realname);
}
@ -1634,5 +1694,5 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
_dl_signal_error (errno, name, N_("cannot open shared object file"));
}
return _dl_map_object_from_fd (name, fd, realname, loader, type, mode);
return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode);
}