mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
sanitize path_walk() mess
New helper: path_lookupat(). Basically, what do_path_lookup() boils to modulo -ECHILD/-ESTALE handler. path_walk* family is gone; vfs_path_lookup() is using link_path_walk() directly, do_path_lookup() and do_filp_open() are using path_lookupat(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
52094c8a06
commit
ee0827cd6b
1 changed files with 56 additions and 92 deletions
148
fs/namei.c
148
fs/namei.c
|
@ -1520,59 +1520,6 @@ return_err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int path_walk_rcu(const char *name, struct nameidata *nd)
|
|
||||||
{
|
|
||||||
current->total_link_count = 0;
|
|
||||||
|
|
||||||
return link_path_walk(name, nd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int path_walk_simple(const char *name, struct nameidata *nd)
|
|
||||||
{
|
|
||||||
current->total_link_count = 0;
|
|
||||||
|
|
||||||
return link_path_walk(name, nd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int path_walk(const char *name, struct nameidata *nd)
|
|
||||||
{
|
|
||||||
struct path save = nd->path;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
current->total_link_count = 0;
|
|
||||||
|
|
||||||
/* make sure the stuff we saved doesn't go away */
|
|
||||||
path_get(&save);
|
|
||||||
|
|
||||||
result = link_path_walk(name, nd);
|
|
||||||
if (result == -ESTALE) {
|
|
||||||
/* nd->path had been dropped */
|
|
||||||
current->total_link_count = 0;
|
|
||||||
nd->path = save;
|
|
||||||
nd->inode = save.dentry->d_inode;
|
|
||||||
path_get(&nd->path);
|
|
||||||
nd->flags |= LOOKUP_REVAL;
|
|
||||||
result = link_path_walk(name, nd);
|
|
||||||
}
|
|
||||||
|
|
||||||
path_put(&save);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void path_finish_rcu(struct nameidata *nd)
|
|
||||||
{
|
|
||||||
if (nd->flags & LOOKUP_RCU) {
|
|
||||||
/* RCU dangling. Cancel it. */
|
|
||||||
nd->flags &= ~LOOKUP_RCU;
|
|
||||||
nd->root.mnt = NULL;
|
|
||||||
rcu_read_unlock();
|
|
||||||
br_read_unlock(vfsmount_lock);
|
|
||||||
}
|
|
||||||
if (nd->file)
|
|
||||||
fput(nd->file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
|
static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
@ -1697,7 +1644,7 @@ out_fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
|
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
|
||||||
static int do_path_lookup(int dfd, const char *name,
|
static int path_lookupat(int dfd, const char *name,
|
||||||
unsigned int flags, struct nameidata *nd)
|
unsigned int flags, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -1716,29 +1663,45 @@ static int do_path_lookup(int dfd, const char *name,
|
||||||
* be handled by restarting a traditional ref-walk (which will always
|
* be handled by restarting a traditional ref-walk (which will always
|
||||||
* be able to complete).
|
* be able to complete).
|
||||||
*/
|
*/
|
||||||
retval = path_init_rcu(dfd, name, flags, nd);
|
if (flags & LOOKUP_RCU)
|
||||||
|
retval = path_init_rcu(dfd, name, flags, nd);
|
||||||
|
else
|
||||||
|
retval = path_init(dfd, name, flags, nd);
|
||||||
|
|
||||||
if (unlikely(retval))
|
if (unlikely(retval))
|
||||||
return retval;
|
return retval;
|
||||||
retval = path_walk_rcu(name, nd);
|
|
||||||
path_finish_rcu(nd);
|
current->total_link_count = 0;
|
||||||
|
retval = link_path_walk(name, nd);
|
||||||
|
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
/* RCU dangling. Cancel it. */
|
||||||
|
nd->flags &= ~LOOKUP_RCU;
|
||||||
|
nd->root.mnt = NULL;
|
||||||
|
rcu_read_unlock();
|
||||||
|
br_read_unlock(vfsmount_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nd->file) {
|
||||||
|
fput(nd->file);
|
||||||
|
nd->file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (nd->root.mnt) {
|
if (nd->root.mnt) {
|
||||||
path_put(&nd->root);
|
path_put(&nd->root);
|
||||||
nd->root.mnt = NULL;
|
nd->root.mnt = NULL;
|
||||||
}
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(retval == -ECHILD || retval == -ESTALE)) {
|
static int do_path_lookup(int dfd, const char *name,
|
||||||
/* slower, locked walk */
|
unsigned int flags, struct nameidata *nd)
|
||||||
if (retval == -ESTALE)
|
{
|
||||||
flags |= LOOKUP_REVAL;
|
int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd);
|
||||||
retval = path_init(dfd, name, flags, nd);
|
if (unlikely(retval == -ECHILD))
|
||||||
if (unlikely(retval))
|
retval = path_lookupat(dfd, name, flags, nd);
|
||||||
return retval;
|
if (unlikely(retval == -ESTALE))
|
||||||
retval = path_walk(name, nd);
|
retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
|
||||||
if (nd->root.mnt) {
|
|
||||||
path_put(&nd->root);
|
|
||||||
nd->root.mnt = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(!retval)) {
|
if (likely(!retval)) {
|
||||||
if (unlikely(!audit_dummy_context())) {
|
if (unlikely(!audit_dummy_context())) {
|
||||||
|
@ -1746,7 +1709,6 @@ static int do_path_lookup(int dfd, const char *name,
|
||||||
audit_inode(name, nd->path.dentry);
|
audit_inode(name, nd->path.dentry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1776,7 +1738,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
||||||
const char *name, unsigned int flags,
|
const char *name, unsigned int flags,
|
||||||
struct nameidata *nd)
|
struct nameidata *nd)
|
||||||
{
|
{
|
||||||
int retval;
|
int result;
|
||||||
|
|
||||||
/* same as do_path_lookup */
|
/* same as do_path_lookup */
|
||||||
nd->last_type = LAST_ROOT;
|
nd->last_type = LAST_ROOT;
|
||||||
|
@ -1790,15 +1752,27 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
||||||
path_get(&nd->root);
|
path_get(&nd->root);
|
||||||
nd->inode = nd->path.dentry->d_inode;
|
nd->inode = nd->path.dentry->d_inode;
|
||||||
|
|
||||||
retval = path_walk(name, nd);
|
current->total_link_count = 0;
|
||||||
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
|
|
||||||
|
result = link_path_walk(name, nd);
|
||||||
|
if (result == -ESTALE) {
|
||||||
|
/* nd->path had been dropped */
|
||||||
|
current->total_link_count = 0;
|
||||||
|
nd->path.dentry = dentry;
|
||||||
|
nd->path.mnt = mnt;
|
||||||
|
nd->inode = dentry->d_inode;
|
||||||
|
path_get(&nd->path);
|
||||||
|
nd->flags |= LOOKUP_REVAL;
|
||||||
|
result = link_path_walk(name, nd);
|
||||||
|
}
|
||||||
|
if (unlikely(!result && !audit_dummy_context() && nd->path.dentry &&
|
||||||
nd->inode))
|
nd->inode))
|
||||||
audit_inode(name, nd->path.dentry);
|
audit_inode(name, nd->path.dentry);
|
||||||
|
|
||||||
path_put(&nd->root);
|
path_put(&nd->root);
|
||||||
nd->root.mnt = NULL;
|
nd->root.mnt = NULL;
|
||||||
|
|
||||||
return retval;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dentry *__lookup_hash(struct qstr *name,
|
static struct dentry *__lookup_hash(struct qstr *name,
|
||||||
|
@ -2483,24 +2457,14 @@ out_filp2:
|
||||||
|
|
||||||
creat:
|
creat:
|
||||||
/* OK, have to create the file. Find the parent. */
|
/* OK, have to create the file. Find the parent. */
|
||||||
error = path_init_rcu(dfd, pathname,
|
error = path_lookupat(dfd, pathname, LOOKUP_PARENT | LOOKUP_RCU, &nd);
|
||||||
LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
|
if (unlikely(error == -ECHILD))
|
||||||
if (error)
|
error = path_lookupat(dfd, pathname, LOOKUP_PARENT, &nd);
|
||||||
goto out_filp;
|
if (unlikely(error == -ESTALE)) {
|
||||||
error = path_walk_rcu(pathname, &nd);
|
|
||||||
path_finish_rcu(&nd);
|
|
||||||
if (unlikely(error == -ECHILD || error == -ESTALE)) {
|
|
||||||
/* slower, locked walk */
|
|
||||||
if (error == -ESTALE) {
|
|
||||||
reval:
|
reval:
|
||||||
flags |= LOOKUP_REVAL;
|
flags |= LOOKUP_REVAL;
|
||||||
}
|
error = path_lookupat(dfd, pathname,
|
||||||
error = path_init(dfd, pathname,
|
LOOKUP_PARENT | LOOKUP_REVAL, &nd);
|
||||||
LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
|
|
||||||
if (error)
|
|
||||||
goto out_filp;
|
|
||||||
|
|
||||||
error = path_walk_simple(pathname, &nd);
|
|
||||||
}
|
}
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto out_filp;
|
goto out_filp;
|
||||||
|
|
Loading…
Reference in a new issue