svn commit: r200509 - stable/8/libexec/rtld-elf

Bruce Evans brde at optusnet.com.au
Mon Dec 14 08:08:44 PST 2009


On Mon, 14 Dec 2009, Robert Watson wrote:

> Log:
>  Merge r197808 from head to stable/8:
>
>    In rtld's map_object(), use pread(..., 0) rather than read() to read the
>    ELF header from the front of the file.  As all other I/O on the binary
>    is done using mmap(), this avoids the need for seek privileges on the
>    file descriptor during run-time linking.

Doesn't/shouldn't pread() require seek privileges?  It certainly uses them.

BTW, its man page contradicts and/or is incomplete about what happens for
unseekable files:

%      On objects capable of seeking, the read() starts at a position given by
                                       ^^^^^^^^^^^^^^^^^^^^^^
Should say "read() and readv() start at the"

%      the pointer associated with d (see lseek(2)).  Upon return from read(),
        ... or readv()
%      the pointer is incremented by the number of bytes actually read.
% 
%      Objects that are not capable of seeking always read from the current
%      position.  The value of the pointer associated with such an object is
%      undefined.

The second paragraph applies to all members of the read() family (though
perhaps it was only intended intended to apply to read() and readv()
like it did before pread() existed), and is wrong for pread() and
preadv().  Instead, pread() attemps to determine seekability using the
DFLAG_SEEKABLE flag in the same way as lseek(); if this is set, then
pread() correctly determines non-seekability and returns ESPIPE, but
if this is not set the pread() assumes that the file is seekable even
if it isn't, and I think the error is not detected later.  (For the
corresponding bug in lseek(2), the error is certainly not detected
later, since there is no "later".  pread() is presumably bug for bug
compatible with this and reads from the current non-position for
unseekable files when the error is not detected.)

% ERRORS
%      The read(), readv(), pread() and preadv() system calls will succeed
%      unless:
% ...
%      The pread() and preadv() system calls may also return the following
%      errors:
% 
%      [EINVAL]           The offset value was negative.
% 
%      [ESPIPE]           The file descriptor is associated with a pipe, socket,
%                         or FIFO.

This says that pread() may work correctly for some non-seekable files.
Since it only says "may", it doesn't quite contradict the above.  Also,
the list of file types for which it may work correctly is incomplete.
It is unclear exactly which file types work correctly, since DFLAG_SEEKABLE
is set for all files of type "vnop" (see struct fileops vnops).  I
think this covers lots of unseekable irregular regular files in weird
file systems like procfs.  It is also set for all device files, but
most devices aren't seekable.  It is not set for uipc shm and sem
files, so I think ESPIPE can be returned for these file types,
contradicting the above and the corresponding list in lseek.2, but
this is unimportant since pread[v] would fail with EOPNOTSUPP if it
got past the ESPIPE.

Similarly for write.2 and lseek.2.

Extra for lseek.2: it says "some devices are incapable of seeking"
where it should say "some files are incapable of seeking" and/or give more
details as above (even current man page for pread gives more details
relevant to lseek than does lseek's man page!).

Extra for write.2 (unrelated): where read.2 gives some details for
short reads (it says that they don't happen for "normal" files, write.2
says less and doesn't mention "normal" files, but it should say more
because "normal" operation is more important.  Which files are normal
is undocumented and unclear.

Bruce


More information about the svn-src-stable-8 mailing list