Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 234293
b: refs/heads/master
c: b356379
h: refs/heads/master
i:
  234291: 04dccf7
v: v3
  • Loading branch information
Al Viro committed Mar 15, 2011
1 parent 416ec78 commit 58435fa
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 55 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ce0525449da56444948c368f52e10f3db0465338
refs/heads/master: b356379a020bb7197603118bb1cbc903963aa198
104 changes: 50 additions & 54 deletions trunk/fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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_symlink(&next, nd);
if (err)
return err;
}
Expand All @@ -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);
Expand Down

0 comments on commit 58435fa

Please sign in to comment.