From eead19115329c5615ba03cbaf1c3fe24c14858a3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 16 Oct 2007 23:25:38 -0700 Subject: [PATCH] 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 Cc: Josef 'Jeff' Sipek Cc: Miklos Szeredi Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 58 +++++++++++++++++++++++++++---------------- fs/sysfs/dir.c | 3 +-- include/linux/namei.h | 4 +-- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index b40b8084eef..bab0d19a2e3 100644 --- a/fs/namei.c +++ b/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 @@ out: * 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) +static struct dentry *lookup_hash(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); + err = permission(nd->dentry->d_inode, MAY_EXEC, nd); if (err) - goto out; - - dentry = __lookup_hash_kern(name, base, nd); -out: - return dentry; -} - -static struct dentry *lookup_hash(struct nameidata *nd) -{ + 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, diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9161db4d6b5..d3118d48293 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -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); diff --git a/include/linux/namei.h b/include/linux/namei.h index 6c38efbd810..4cb4f8d2f78 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -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 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_len(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 **); -- 2.41.0