aboutsummaryrefslogtreecommitdiffstats
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 b40b8084eefc..bab0d19a2e36 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,
1273 return err; 1273 return err;
1274} 1274}
1275 1275
1276static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) 1276static struct dentry *__lookup_hash(struct qstr *name,
1277 struct dentry *base, struct nameidata *nd)
1277{ 1278{
1278 struct dentry *dentry; 1279 struct dentry *dentry;
1279 struct inode *inode; 1280 struct inode *inode;
@@ -1313,31 +1314,18 @@ out:
1313 * needs parent already locked. Doesn't follow mounts. 1314 * needs parent already locked. Doesn't follow mounts.
1314 * SMP-safe. 1315 * SMP-safe.
1315 */ 1316 */
1316static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) 1317static struct dentry *lookup_hash(struct nameidata *nd)
1317{ 1318{
1318 struct dentry *dentry;
1319 struct inode *inode;
1320 int err; 1319 int err;
1321 1320
1322 inode = base->d_inode; 1321 err = permission(nd->dentry->d_inode, MAY_EXEC, nd);
1323
1324 err = permission(inode, MAY_EXEC, nd);
1325 dentry = ERR_PTR(err);
1326 if (err) 1322 if (err)
1327 goto out; 1323 return ERR_PTR(err);
1328
1329 dentry = __lookup_hash_kern(name, base, nd);
1330out:
1331 return dentry;
1332}
1333
1334static struct dentry *lookup_hash(struct nameidata *nd)
1335{
1336 return __lookup_hash(&nd->last, nd->dentry, nd); 1324 return __lookup_hash(&nd->last, nd->dentry, nd);
1337} 1325}
1338 1326
1339/* SMP-safe */ 1327static int __lookup_one_len(const char *name, struct qstr *this,
1340static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) 1328 struct dentry *base, int len)
1341{ 1329{
1342 unsigned long hash; 1330 unsigned long hash;
1343 unsigned int c; 1331 unsigned int c;
@@ -1358,6 +1346,17 @@ static inline int __lookup_one_len(const char *name, struct qstr *this, struct d
1358 return 0; 1346 return 0;
1359} 1347}
1360 1348
1349/**
1350 * lookup_one_len: filesystem helper to lookup single pathname component
1351 * @name: pathname component to lookup
1352 * @base: base directory to lookup from
1353 * @len: maximum length @len should be interpreted to
1354 *
1355 * Note that this routine is purely a helper for filesystem useage and should
1356 * not be called by generic code. Also note that by using this function to
1357 * nameidata argument is passed to the filesystem methods and a filesystem
1358 * using this helper needs to be prepared for that.
1359 */
1361struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) 1360struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
1362{ 1361{
1363 int err; 1362 int err;
@@ -1366,18 +1365,33 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
1366 err = __lookup_one_len(name, &this, base, len); 1365 err = __lookup_one_len(name, &this, base, len);
1367 if (err) 1366 if (err)
1368 return ERR_PTR(err); 1367 return ERR_PTR(err);
1368
1369 err = permission(base->d_inode, MAY_EXEC, NULL);
1370 if (err)
1371 return ERR_PTR(err);
1369 return __lookup_hash(&this, base, NULL); 1372 return __lookup_hash(&this, base, NULL);
1370} 1373}
1371 1374
1372struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) 1375/**
1376 * lookup_one_noperm - bad hack for sysfs
1377 * @name: pathname component to lookup
1378 * @base: base directory to lookup from
1379 *
1380 * This is a variant of lookup_one_len that doesn't perform any permission
1381 * checks. It's a horrible hack to work around the braindead sysfs
1382 * architecture and should not be used anywhere else.
1383 *
1384 * DON'T USE THIS FUNCTION EVER, thanks.
1385 */
1386struct dentry *lookup_one_noperm(const char *name, struct dentry *base)
1373{ 1387{
1374 int err; 1388 int err;
1375 struct qstr this; 1389 struct qstr this;
1376 1390
1377 err = __lookup_one_len(name, &this, base, len); 1391 err = __lookup_one_len(name, &this, base, strlen(name));
1378 if (err) 1392 if (err)
1379 return ERR_PTR(err); 1393 return ERR_PTR(err);
1380 return __lookup_hash_kern(&this, base, NULL); 1394 return __lookup_hash(&this, base, NULL);
1381} 1395}
1382 1396
1383int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, 1397int 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 9161db4d6b5c..d3118d482935 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -112,8 +112,7 @@ struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
112 /* look it up */ 112 /* look it up */
113 parent = dentry; 113 parent = dentry;
114 mutex_lock(&parent->d_inode->i_mutex); 114 mutex_lock(&parent->d_inode->i_mutex);
115 dentry = lookup_one_len_kern(cur->s_name, parent, 115 dentry = lookup_one_noperm(cur->s_name, parent);
116 strlen(cur->s_name));
117 mutex_unlock(&parent->d_inode->i_mutex); 116 mutex_unlock(&parent->d_inode->i_mutex);
118 dput(parent); 117 dput(parent);
119 118
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 6c38efbd810f..4cb4f8d2f78d 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
81extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); 81extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
82extern void release_open_intent(struct nameidata *); 82extern void release_open_intent(struct nameidata *);
83 83
84extern struct dentry * lookup_one_len(const char *, struct dentry *, int); 84extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
85extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int); 85extern struct dentry *lookup_one_noperm(const char *, struct dentry *);
86 86
87extern int follow_down(struct vfsmount **, struct dentry **); 87extern int follow_down(struct vfsmount **, struct dentry **);
88extern int follow_up(struct vfsmount **, struct dentry **); 88extern int follow_up(struct vfsmount **, struct dentry **);