[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