[osiris-devel] Re: Hunting down lstat "bug" in scanner
Brian Wotring
brian at hostintegrity.com
Fri Sep 16 21:26:26 EDT 2005
Awesome. Thanks for testing that. I'll verify this and the getdents()
portions.
-brian
Douglas K. Fischer wrote:
> Bingo. I was readily able to replicate it, and the problem appears to be
> with the exit conditions of osi_readdir(). The
>
> if( dp->d_reclen <= 0 || dp->d_reclen > d->dd_len + 1 - d->dd_loc )
>
> statement does not correctly catch the case when we've reached the last
> dirent entry that was returned by the fetch. We need to look at dd_size
> compared with dd_loc to determine if we've reached the end of the
> fetched entries (from glibc readdir() code). The outcome is otherwise
> determined by the contents of the buffer past dd_size. In most of the
> cases the resulting next read would fail the above condition and exit
> with NULL, or fail one of the other NULL-returning conditions. However,
> in some cases the buffer contents were such that a non-NULL return resulted.
>
> I've attached a version of osi_readdir() that should solve this, as well
> as deal with the aforementioned case where we need to perform one or
> more additional getdirentries() in order to get the rest of the dirents.
> The code is very similar to the glibc readdir() code, so it should
> behave is almost exactly the same manner.
>
> I don't have access to a system with getdents() instead of
> getdirentries(), so I can't vouch for correct operation of the
> re-fetching with getdents(). However, I've attached a simple patch to my
> version of osi_readdir() that will disable the re-fetching for
> getdents() if it doesn't work. (Provided that the underlying system call
> keeps the fd seek pointer at the end of the last read from getdents(),
> this should work I believe.)
>
> Also, the restructuring of the osi_readdir() loop resulted in the
> exclusion of the IRIX #ifndef around the zero inode checking. This may
> or may not cause the problem to return on IRIX. I didn't see anything in
> the glibc code that was different for IRIX. Was it all versions of IRIX
> or a specific one? I've attached another patch in case this does cause a
> problem with IRIX.
>
> Cheers,
>
> Doug
>
> Brian Wotring wrote:
>
>
>>Attached is a sample application that makes use of osi_readdir() to
>>traverse a directory and list the entries, the same way the privsep
>>code does.
>>
>>-brian
>>
>>Brian Wotring wrote:
>>
>>
>>>At this point, it makes sense to write a test app that makes use of
>>>the osi_readdir() code to see if this problem can be duplicated.
>>>
>>>If I am unable to duplicate it, do you have a system that
>>>demonstrates this problem that you would be willing to try to
>>>duplicate it on? I'll post the app shortly.
>>>
>>>-brian
>>
>
>
>
> ------------------------------------------------------------------------
>
> struct dirent *osi_readdir( OSI_DIRECTORY *d )
> {
> #if defined(HAVE_GETDIRENTRIES) || defined(HAVE_GETDENTS)
>
> register struct dirent *dp;
>
> if( d == NULL )
> {
> return NULL;
> }
>
> do
> {
> /*
> * We want to fetch new dirents if either:
> * 1. This is our first read of the directory
> * 2. We've reached the end of a previous fetch for this directory
> * and there might be more dirents to fetch
> */
> if( d->dd_loc >= d->dd_size )
> {
> #ifdef HAVE_GETDIRENTRIES
> d->dd_size = getdirentries( d->dd_fd, d->buffer,
> d->dd_len, &d->dd_seek );
> #else
> d->dd_size = getdents( d->dd_fd, (struct dirent *)d->buffer,
> d->dd_len );
> #endif
>
> if( d->dd_size <= 0 )
> {
> return NULL;
> }
>
> d->dd_loc = 0; /* Reset if this is a secondary fetch */
> }
>
> dp = (struct dirent *)(d->buffer + d->dd_loc);
>
> if( dp == NULL )
> {
> return NULL;
> }
>
> d->dd_loc += dp->d_reclen;
>
> } while( dp->d_ino == 0 ); /* Skip deleted entries */
>
> d->file = dp;
>
> if( d->file->d_name[0] == '\0' )
> {
> return NULL;
> }
>
> return dp;
>
> #endif /* HAVE_GETDIRENTRIES */
>
> return NULL;
> }
>
>
> ------------------------------------------------------------------------
>
> --- osi_readdir.c.orig Thu Sep 15 11:37:48 2005
> +++ osi_readdir.c Thu Sep 15 11:39:24 2005
> @@ -15,17 +15,19 @@
> * We want to fetch new dirents if either:
> * 1. This is our first read of the directory
> * 2. We've reached the end of a previous fetch for this directory
> - * and there might be more dirents to fetch
> + * and there might be more dirents to fetch (getdirentries only)
> */
> + #ifdef HAVE_GETDIRENTRIES
> if( d->dd_loc >= d->dd_size )
> {
> - #ifdef HAVE_GETDIRENTRIES
> d->dd_size = getdirentries( d->dd_fd, d->buffer,
> d->dd_len, &d->dd_seek );
> - #else
> + #else
> + if( d->dd_loc == 0 )
> + {
> d->dd_size = getdents( d->dd_fd, (struct dirent *)d->buffer,
> d->dd_len );
> - #endif
> + #endif
>
> if( d->dd_size <= 0 )
> {
>
>
> ------------------------------------------------------------------------
>
> --- osi_readdir.c.orig Thu Sep 15 11:37:48 2005
> +++ osi_readdir.c Thu Sep 15 12:06:16 2005
> @@ -44,7 +44,11 @@
>
> d->dd_loc += dp->d_reclen;
>
> +#ifndef SYSTEM_IRIX
> } while( dp->d_ino == 0 ); /* Skip deleted entries */
> +#else
> + } while( 1 );
> +#endif
>
> d->file = dp;
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> osiris-devel mailing list
> osiris-devel at lists.shmoo.com
> https://lists.shmoo.com/mailman/listinfo/osiris-devel
More information about the osiris-devel
mailing list