@ -779,40 +779,6 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
return error ;
}
/*
* This limits recursive symlink follows to 8 , while
* limiting consecutive symlinks to 40.
*
* Without that kind of total limit , nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups .
*/
static inline int do_follow_link ( struct path * path , struct nameidata * nd )
{
void * cookie ;
int err = - ELOOP ;
if ( current - > link_count > = MAX_NESTED_LINKS )
goto loop ;
if ( current - > total_link_count > = 40 )
goto loop ;
BUG_ON ( nd - > depth > = MAX_NESTED_LINKS ) ;
cond_resched ( ) ;
current - > link_count + + ;
current - > total_link_count + + ;
nd - > depth + + ;
err = __do_follow_link ( path , nd , & cookie ) ;
if ( ! IS_ERR ( cookie ) & & path - > dentry - > d_inode - > i_op - > put_link )
path - > dentry - > d_inode - > i_op - > put_link ( path - > dentry , nd , cookie ) ;
path_put ( path ) ;
current - > link_count - - ;
nd - > depth - - ;
return err ;
loop :
path_put_conditional ( path , nd ) ;
path_put ( & nd - > path ) ;
return err ;
}
static int follow_up_rcu ( struct path * path )
{
struct vfsmount * parent ;
@ -1366,6 +1332,52 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
return 0 ;
}
/*
* This limits recursive symlink follows to 8 , while
* limiting consecutive symlinks to 40.
*
* Without that kind of total limit , nasty chains of consecutive
* symlinks can cause almost arbitrarily long lookups .
*/
static inline int nested_symlink ( struct path * path , struct nameidata * nd )
{
int res ;
BUG_ON ( nd - > depth > = MAX_NESTED_LINKS ) ;
if ( unlikely ( current - > link_count > = MAX_NESTED_LINKS ) ) {
path_put_conditional ( path , nd ) ;
path_put ( & nd - > path ) ;
return - ELOOP ;
}
nd - > depth + + ;
current - > link_count + + ;
do {
struct path link = * path ;
void * cookie ;
if ( unlikely ( current - > total_link_count > = 40 ) ) {
path_put_conditional ( path , nd ) ;
path_put ( & nd - > path ) ;
res = - ELOOP ;
break ;
}
cond_resched ( ) ;
current - > total_link_count + + ;
res = __do_follow_link ( & link , nd , & cookie ) ;
if ( ! res )
res = walk_component ( nd , path , & nd - > last ,
nd - > last_type , LOOKUP_FOLLOW ) ;
if ( ! IS_ERR ( cookie ) & & link . dentry - > d_inode - > i_op - > put_link )
link . dentry - > d_inode - > i_op - > put_link ( link . dentry , nd , cookie ) ;
path_put ( & link ) ;
} while ( res > 0 ) ;
current - > link_count - - ;
nd - > depth - - ;
return res ;
}
/*
* Name resolution .
* This is the basic name resolution function , turning a pathname into
@ -1385,9 +1397,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
if ( ! * name )
return 0 ;
if ( nd - > depth )
lookup_flags = LOOKUP_FOLLOW | ( nd - > flags & LOOKUP_CONTINUE ) ;
/* At this point we know we have a real path component. */
for ( ; ; ) {
unsigned long hash ;
@ -1440,14 +1449,14 @@ static int link_path_walk(const char *name, struct nameidata *nd)
goto last_component ;
while ( * + + name = = ' / ' ) ;
if ( ! * name )
goto last_with_slashes ;
goto last_component ;
err = walk_component ( nd , & next , & this , type , LOOKUP_FOLLOW ) ;
if ( err < 0 )
return err ;
if ( err ) {
err = do_follow_ link( & next , nd ) ;
err = nested_sym link( & next , nd ) ;
if ( err )
return err ;
}
@ -1457,24 +1466,11 @@ static int link_path_walk(const char *name, struct nameidata *nd)
continue ;
/* here ends the main loop */
last_with_slashes :
lookup_flags | = LOOKUP_FOLLOW | LOOKUP_DIRECTORY ;
last_component :
/* Clear LOOKUP_CONTINUE iff it was previously unset */
nd - > flags & = lookup_flags | ~ LOOKUP_CONTINUE ;
if ( lookup_flags & LOOKUP_PARENT ) {
nd - > last = this ;
nd - > last_type = type ;
return 0 ;
}
err = walk_component ( nd , & next , & this , type , LOOKUP_FOLLOW ) ;
if ( err < 0 )
return err ;
if ( err ) {
err = do_follow_link ( & next , nd ) ;
if ( err )
return err ;
}
nd - > last = this ;
nd - > last_type = type ;
return 0 ;
}
terminate_walk ( nd ) ;