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: Christoph 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ebb3e820b8
commit
eead191153
3 changed files with 41 additions and 28 deletions
62
fs/namei.c
62
fs/namei.c
|
@ -1273,7 +1273,8 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
|
|||
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 inode *inode;
|
||||
|
@ -1313,31 +1314,18 @@ static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry
|
|||
* needs parent already locked. Doesn't follow mounts.
|
||||
* SMP-safe.
|
||||
*/
|
||||
static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
int err;
|
||||
|
||||
inode = base->d_inode;
|
||||
|
||||
err = permission(inode, MAY_EXEC, nd);
|
||||
dentry = ERR_PTR(err);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dentry = __lookup_hash_kern(name, base, nd);
|
||||
out:
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static struct dentry *lookup_hash(struct nameidata *nd)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = permission(nd->dentry->d_inode, MAY_EXEC, nd);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&nd->last, nd->dentry, nd);
|
||||
}
|
||||
|
||||
/* SMP-safe */
|
||||
static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
|
||||
static int __lookup_one_len(const char *name, struct qstr *this,
|
||||
struct dentry *base, int len)
|
||||
{
|
||||
unsigned long hash;
|
||||
unsigned int c;
|
||||
|
@ -1358,26 +1346,52 @@ static inline int __lookup_one_len(const char *name, struct qstr *this, struct d
|
|||
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)
|
||||
{
|
||||
int err;
|
||||
struct qstr this;
|
||||
|
||||
err = __lookup_one_len(name, &this, base, len);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = permission(base->d_inode, MAY_EXEC, NULL);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
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;
|
||||
struct qstr this;
|
||||
|
||||
err = __lookup_one_len(name, &this, base, len);
|
||||
err = __lookup_one_len(name, &this, base, strlen(name));
|
||||
if (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,
|
||||
|
|
|
@ -112,8 +112,7 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
|
|||
/* look it up */
|
||||
parent = dentry;
|
||||
mutex_lock(&parent->d_inode->i_mutex);
|
||||
dentry = lookup_one_len_kern(cur->s_name, parent,
|
||||
strlen(cur->s_name));
|
||||
dentry = lookup_one_noperm(cur->s_name, parent);
|
||||
mutex_unlock(&parent->d_inode->i_mutex);
|
||||
dput(parent);
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
|
|||
extern void release_open_intent(struct nameidata *);
|
||||
|
||||
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_up(struct vfsmount **, struct dentry **);
|
||||
|
|
Loading…
Reference in a new issue