Commit eead1911 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds

partially fix up the lookup_one_noperm mess

Try to fix the mess created by sysfs braindamage.

 - refactor code internal to fs/namei.c a little to avoid too much
   duplication:
	o __lookup_hash_kern is renamed back to __lookup_hash
	o the old __lookup_hash goes away, permission checks moves to
	  the two callers
	o useless inline qualifiers on above functions go away
 - lookup_one_len_kern loses it's last argument and is renamed to
   lookup_one_noperm to make it's useage a little more clear
 - added kerneldoc comments to describe lookup_one_len aswell as
   lookup_one_noperm and make it very clear that no one should use
   the latter ever.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Cc: Josef 'Jeff' Sipek <jsipek@cs.sunysb.edu>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ebb3e820
...@@ -1273,7 +1273,8 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, ...@@ -1273,7 +1273,8 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
return err; return err;
} }
static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) static struct dentry *__lookup_hash(struct qstr *name,
struct dentry *base, struct nameidata *nd)
{ {
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
...@@ -1313,31 +1314,18 @@ out: ...@@ -1313,31 +1314,18 @@ out:
* needs parent already locked. Doesn't follow mounts. * needs parent already locked. Doesn't follow mounts.
* SMP-safe. * SMP-safe.
*/ */
static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) static struct dentry *lookup_hash(struct nameidata *nd)
{ {
struct dentry *dentry;
struct inode *inode;
int err; int err;
inode = base->d_inode; err = permission(nd->dentry->d_inode, MAY_EXEC, nd);
err = permission(inode, MAY_EXEC, nd);
dentry = ERR_PTR(err);
if (err) if (err)
goto out; return ERR_PTR(err);
dentry = __lookup_hash_kern(name, base, nd);
out:
return dentry;
}
static struct dentry *lookup_hash(struct nameidata *nd)
{
return __lookup_hash(&nd->last, nd->dentry, nd); return __lookup_hash(&nd->last, nd->dentry, nd);
} }
/* SMP-safe */ static int __lookup_one_len(const char *name, struct qstr *this,
static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) struct dentry *base, int len)
{ {
unsigned long hash; unsigned long hash;
unsigned int c; unsigned int c;
...@@ -1358,26 +1346,52 @@ static inline int __lookup_one_len(const char *name, struct qstr *this, struct d ...@@ -1358,26 +1346,52 @@ static inline int __lookup_one_len(const char *name, struct qstr *this, struct d
return 0; return 0;
} }
/**
* lookup_one_len: filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* @base: base directory to lookup from
* @len: maximum length @len should be interpreted to
*
* Note that this routine is purely a helper for filesystem useage and should
* not be called by generic code. Also note that by using this function to
* nameidata argument is passed to the filesystem methods and a filesystem
* using this helper needs to be prepared for that.
*/
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
{ {
int err; int err;
struct qstr this; struct qstr this;
err = __lookup_one_len(name, &this, base, len); err = __lookup_one_len(name, &this, base, len);
if (err)
return ERR_PTR(err);
err = permission(base->d_inode, MAY_EXEC, NULL);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return __lookup_hash(&this, base, NULL); return __lookup_hash(&this, base, NULL);
} }
struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) /**
* lookup_one_noperm - bad hack for sysfs
* @name: pathname component to lookup
* @base: base directory to lookup from
*
* This is a variant of lookup_one_len that doesn't perform any permission
* checks. It's a horrible hack to work around the braindead sysfs
* architecture and should not be used anywhere else.
*
* DON'T USE THIS FUNCTION EVER, thanks.
*/
struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
{ {
int err; int err;
struct qstr this; struct qstr this;
err = __lookup_one_len(name, &this, base, len); err = __lookup_one_len(name, &this, base, strlen(name));
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
return __lookup_hash_kern(&this, base, NULL); return __lookup_hash(&this, base, NULL);
} }
int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
......
...@@ -112,8 +112,7 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) ...@@ -112,8 +112,7 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
/* look it up */ /* look it up */
parent = dentry; parent = dentry;
mutex_lock(&parent->d_inode->i_mutex); mutex_lock(&parent->d_inode->i_mutex);
dentry = lookup_one_len_kern(cur->s_name, parent, dentry = lookup_one_noperm(cur->s_name, parent);
strlen(cur->s_name));
mutex_unlock(&parent->d_inode->i_mutex); mutex_unlock(&parent->d_inode->i_mutex);
dput(parent); dput(parent);
......
...@@ -81,8 +81,8 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry ...@@ -81,8 +81,8 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
extern void release_open_intent(struct nameidata *); extern void release_open_intent(struct nameidata *);
extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int); extern struct dentry *lookup_one_noperm(const char *, struct dentry *);
extern int follow_down(struct vfsmount **, struct dentry **); extern int follow_down(struct vfsmount **, struct dentry **);
extern int follow_up(struct vfsmount **, struct dentry **); extern int follow_up(struct vfsmount **, struct dentry **);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment