summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c58
-rw-r--r--fs/sysfs/dir.c3
-rw-r--r--include/linux/namei.h4
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,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,
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 **);