diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 58 |
1 files changed, 36 insertions, 22 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,6 +1346,17 @@ 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; @@ -1366,18 +1365,33 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int 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) + 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, |