Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Mar 1996 22:35:26 +1100
From:      Bruce Evans <bde@zeta.org.au>
To:        hackers@FreeBSD.ORG, msmith@atrad.adelaide.edu.au
Subject:   Re: Linuxulator unhappiness...
Message-ID:  <199603011135.WAA10457@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>Heyho people; got a problem here.  I can't be sure whether this has been
>fixed in -current; I don't have the latest 2.2 snap installed (yet).

I seem to remember this being reported and fixed before, but it doesn't
seem to be fixed in -current:

>  4912 idl      CALL  read(0x3,0x3ed008,0x8000)
>  4912 idl      GIO   fd 3 read 32768 bytes
>       "SR\0\^D\0\0\0
>... remainder of 32K read ...
>  4912 idl      RET   read 32768/0x8000
>  4912 idl      CALL  old.lseek(0x3,0xffff8004,0x1)
>  4912 idl      RET   old.lseek 4
>  4912 idl      CALL  read(0x3,0x3ed008,0x8000)
>  4912 idl      RET   read -1 errno 27 File too large
>  4912 idl      CALL  read(0x3,0x3ed008,0x8000)
>  4912 idl      RET   read -1 errno 27 File too large

This is probably caused by bogus types and overflow bugs in linux_file.c
function linux_lseek():

1) the offset is declared as `unsigned long' in `struct linux_seek_args'.
File offsets should normally be signed to avoid problems like the current
one (that's why off_t is signed).

2) the offset is converted to an off_t and passed to lseek.  Its value
began as -32764 and became 0xffff8004 when it was implicitly converted to
an unsigned long and converting it to an off_t leaves it as 0xffff8004.

3) lseek returns the final offset in an array of 2 ints.  The value
of 0x10000004 isn't representable as a Linux off_t, so it should be
an error if it occurs.   It shouldn't be allowed to occur - the final
offset and the result should both be 4.  No error checking is done, so
this value is implicitly converted to 4 and there is no sign of an
error until the next read.  The read fails because the file offset is
0x100000004 and that is too big for the file system.  On a big file
system, read would return EOF.

linux_lseek should use olseek() to do the error checking.  However,
olseek() has similar bugs.  E.g., if the file offset is 0x7fffffff
and the seek is 1 forward, then the final offset is 0x80000000
(+2GB) but the application is told that it is (long)0x80000000 ==
(off_t) 0xffffffff80000000 (-2GB).  It should be what the application
asked for, i.e., -2GB.

>Any ideas?  This is under -stable built yesterday.

linux_lseek() in -stable is essentially the same as in -current.  The
implicit cast of the final value is explicit.  This is a no-op on the
i386 because the i386 is little-endian and ints have the same size as
Linux off_t's and the unportable explicit and implicit casts all work...

Reporting lseek as "old.lseek" is another bug.  The linux syscall
number for lseek is 19, which happens to agree with the FreeBSD syscall
number for old.lseek.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199603011135.WAA10457>