[PATCH] for glibc-2.2 getdents code
Trond Myklebust
trond.myklebust@fys.uio.no
Wed Feb 21 13:17:00 GMT 2001
>>>>> " " == Jakub Jelinek <jakub@redhat.com> writes:
> I thought we're talking here about NFSv2. u32 *
> nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) {
No. The bug occurs with NFSv3 as well. I can provide you with the same
knfsd patch I hacked up for HJ so that you can test this for
yourself...
<snip>
> Here is really up to you if you do ntohl(*p++) or
> (s32)ntohl(*p++) as the protocol has 32-bit cookies, not 64-bit
> cookies. If you use the latter, then no cookie will cause
> EOVERFLOW and the server really does not care, since when you
> pass the cookie back to it, you truncate it to 32bits again.
....
> With NFSv3, of course no sign extension or whatever should
> happen, sys_getdents should return EOVERFLOW if it sees an
> d_off which does not fit and users should use
> getdents64/readdir64, because everything else is wrong (d_off
> value would be truncated).
And this is where the problem lies. Most NFSv3 servers have 32-bit
unsigned readdir cookies for compatibility reasons with 32-bit
clients. For instance on IRIX you can choose the '32bitclients' export
option, in order to get a guarantee that cookies will take values
between 0x0 and 0xFFFFFFFF.
Such a server whould be expected to work against a Linux system even
with the broken (32-bit) implementation of filldir64 that we are stuck
with for linux 2.4.
There are 4 bugs here at work:
1) The kernel is doing a sign extension in filldir64() in passing
from off_t -> loff_t. This needs to be fixed in the kernel.
2) The kernel 32-bit lseek does a similar sign extension.
3) glibc is doing the same in getdents() when trying to determine
whether or not we can copy such a cookie into a struct dirent.
4) glibc is assuming that it's alright to use '-1' unused cookie value.
I just thought of one hack along the lines you suggested that could
accommodate bugs 1), 2) and 3) into the NFS client. One could use
/* Ugly hack for 32-bit sign extension */
u64 nfs_transform_cookie64(u64 cookie)
{
return ((cookie & 0x80000000) != 0) ? (cookie ^ 0xFFFFFFFF00000000) :
cookie;
}
This is a bijection that mimics sign extension on the cases of
interest (works on both NFSv2 and NFSv3).
However that still leaves bug number 4) in glibc.
Cheers,
Trond
More information about the Libc-alpha
mailing list