This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: [PATCH] for glibc-2.2 getdents code
>>>>> " " == 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