PR23254, ld.bfd mishandles file pointers while scanning archive

Best practice is to not mix lseek/read with fseek/fread on the same
underlying file descriptor, as not all stdio implementations will cope.
Since the plugin uses lseek/read while bfd uses fseek/fread this patch
reopens the file for exclusive use by the plugin rather than trying to
restore the file descriptor.  That allows the plugin to read the file
after plugin_call_claim_file too.

bfd/
	PR 23254
	* plugin.c (bfd_plugin_open_input): Allow for possibility of
	nested archives.  Open file again for plugin.
	(try_claim): Don't save and restore file position.  Close file
	if not claimed.
	* sysdep.h (O_BINARY): Define.
ld/
	PR 23254
	* plugin.c (plugin_call_claim_file): Revert 2016-07-19 patch.
	(plugin_object_p): Don't dup file descriptor.
This commit is contained in:
Alan Modra 2018-06-05 21:04:00 +09:30
parent 8347745522
commit 27b0767593
5 changed files with 33 additions and 16 deletions

View File

@ -1,3 +1,12 @@
2018-06-05 Alan Modra <amodra@gmail.com>
PR 23254
* plugin.c (bfd_plugin_open_input): Allow for possibility of
nested archives. Open file again for plugin.
(try_claim): Don't save and restore file position. Close file
if not claimed.
* sysdep.h (O_BINARY): Define.
2018-06-04 Max Filippov <jcmvbkbc@gmail.com>
* elf32-xtensa.c (xtensa_read_table_entries): Make global.

View File

@ -166,14 +166,22 @@ bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
bfd *iobfd;
iobfd = ibfd;
if (ibfd->my_archive && !bfd_is_thin_archive (ibfd->my_archive))
iobfd = ibfd->my_archive;
while (iobfd->my_archive
&& !bfd_is_thin_archive (iobfd->my_archive))
iobfd = iobfd->my_archive;
file->name = iobfd->filename;
if (!iobfd->iostream && !bfd_open_file (iobfd))
return 0;
file->fd = fileno ((FILE *) iobfd->iostream);
/* The plugin API expects that the file descriptor won't be closed
and reused as done by the bfd file cache. So open it again.
dup isn't good enough. plugin IO uses lseek/read while BFD uses
fseek/fread. It isn't wise to mix the unistd and stdio calls on
the same underlying file descriptor. */
file->fd = open (file->name, O_RDONLY | O_BINARY);
if (file->fd < 0)
return 0;
if (iobfd == ibfd)
{
@ -197,12 +205,12 @@ try_claim (bfd *abfd)
int claimed = 0;
struct ld_plugin_input_file file;
file.handle = abfd;
if (!bfd_plugin_open_input (abfd, &file))
return 0;
file.handle = abfd;
off_t cur_offset = lseek (file.fd, 0, SEEK_CUR);
claim_file (&file, &claimed);
lseek (file.fd, cur_offset, SEEK_SET);
if (!claimed)
close (file.fd);
return claimed;
}

View File

@ -108,6 +108,10 @@ extern char *strrchr ();
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
/* Systems that don't already define this, don't need it. */
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef SEEK_SET
#define SEEK_SET 0

View File

@ -1,3 +1,9 @@
2018-06-05 Alan Modra <amodra@gmail.com>
PR 23254
* plugin.c (plugin_call_claim_file): Revert 2016-07-19 patch.
(plugin_object_p): Don't dup file descriptor.
2018-06-05 Flavio Ceolin <flavio.ceolin@intel.com>
* testsuite/ld-elf/elf.exp Run new test.

View File

@ -1053,14 +1053,10 @@ plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
{
if (curplug->claim_file_handler)
{
off_t cur_offset;
enum ld_plugin_status rv;
called_plugin = curplug;
cur_offset = lseek (file->fd, 0, SEEK_CUR);
rv = (*curplug->claim_file_handler) (file, claimed);
if (!*claimed)
lseek (file->fd, cur_offset, SEEK_SET);
called_plugin = NULL;
if (rv != LDPS_OK)
set_plugin_error (curplug->name);
@ -1126,12 +1122,6 @@ plugin_object_p (bfd *ibfd)
}
file.handle = input;
/* The plugin API expects that the file descriptor won't be closed
and reused as done by the bfd file cache. So dup one. */
file.fd = dup (file.fd);
if (file.fd < 0)
return NULL;
input->abfd = abfd;
input->view_buffer.addr = NULL;
input->view_buffer.filesize = 0;