Commit eead19115329c5615ba03cbaf1c3fe24c14858a3
Committed by
Linus Torvalds
1 parent
ebb3e820b8
Exists in
master
and in
20 other branches
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>
Showing 3 changed files with 39 additions and 26 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -1273,7 +1273,8 @@ |
1273 | 1273 | return err; |
1274 | 1274 | } |
1275 | 1275 | |
1276 | -static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) | |
1276 | +static struct dentry *__lookup_hash(struct qstr *name, | |
1277 | + struct dentry *base, struct nameidata *nd) | |
1277 | 1278 | { |
1278 | 1279 | struct dentry *dentry; |
1279 | 1280 | struct inode *inode; |
1280 | 1281 | |
1281 | 1282 | |
1282 | 1283 | |
1283 | 1284 | |
... | ... | @@ -1313,31 +1314,18 @@ |
1313 | 1314 | * needs parent already locked. Doesn't follow mounts. |
1314 | 1315 | * SMP-safe. |
1315 | 1316 | */ |
1316 | -static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) | |
1317 | +static struct dentry *lookup_hash(struct nameidata *nd) | |
1317 | 1318 | { |
1318 | - struct dentry *dentry; | |
1319 | - struct inode *inode; | |
1320 | 1319 | int err; |
1321 | 1320 | |
1322 | - inode = base->d_inode; | |
1323 | - | |
1324 | - err = permission(inode, MAY_EXEC, nd); | |
1325 | - dentry = ERR_PTR(err); | |
1321 | + err = permission(nd->dentry->d_inode, MAY_EXEC, nd); | |
1326 | 1322 | if (err) |
1327 | - goto out; | |
1328 | - | |
1329 | - dentry = __lookup_hash_kern(name, base, nd); | |
1330 | -out: | |
1331 | - return dentry; | |
1332 | -} | |
1333 | - | |
1334 | -static struct dentry *lookup_hash(struct nameidata *nd) | |
1335 | -{ | |
1323 | + return ERR_PTR(err); | |
1336 | 1324 | return __lookup_hash(&nd->last, nd->dentry, nd); |
1337 | 1325 | } |
1338 | 1326 | |
1339 | -/* SMP-safe */ | |
1340 | -static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) | |
1327 | +static int __lookup_one_len(const char *name, struct qstr *this, | |
1328 | + struct dentry *base, int len) | |
1341 | 1329 | { |
1342 | 1330 | unsigned long hash; |
1343 | 1331 | unsigned int c; |
... | ... | @@ -1358,6 +1346,17 @@ |
1358 | 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 | + */ | |
1361 | 1360 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) |
1362 | 1361 | { |
1363 | 1362 | int err; |
1364 | 1363 | |
1365 | 1364 | |
1366 | 1365 | |
... | ... | @@ -1366,18 +1365,33 @@ |
1366 | 1365 | err = __lookup_one_len(name, &this, base, len); |
1367 | 1366 | if (err) |
1368 | 1367 | return ERR_PTR(err); |
1368 | + | |
1369 | + err = permission(base->d_inode, MAY_EXEC, NULL); | |
1370 | + if (err) | |
1371 | + return ERR_PTR(err); | |
1369 | 1372 | return __lookup_hash(&this, base, NULL); |
1370 | 1373 | } |
1371 | 1374 | |
1372 | -struct 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 | + */ | |
1386 | +struct dentry *lookup_one_noperm(const char *name, struct dentry *base) | |
1373 | 1387 | { |
1374 | 1388 | int err; |
1375 | 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 | 1392 | if (err) |
1379 | 1393 | return ERR_PTR(err); |
1380 | - return __lookup_hash_kern(&this, base, NULL); | |
1394 | + return __lookup_hash(&this, base, NULL); | |
1381 | 1395 | } |
1382 | 1396 | |
1383 | 1397 | int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, |
fs/sysfs/dir.c
... | ... | @@ -112,8 +112,7 @@ |
112 | 112 | /* look it up */ |
113 | 113 | parent = dentry; |
114 | 114 | mutex_lock(&parent->d_inode->i_mutex); |
115 | - dentry = lookup_one_len_kern(cur->s_name, parent, | |
116 | - strlen(cur->s_name)); | |
115 | + dentry = lookup_one_noperm(cur->s_name, parent); | |
117 | 116 | mutex_unlock(&parent->d_inode->i_mutex); |
118 | 117 | dput(parent); |
119 | 118 |
include/linux/namei.h
... | ... | @@ -81,8 +81,8 @@ |
81 | 81 | extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); |
82 | 82 | extern void release_open_intent(struct nameidata *); |
83 | 83 | |
84 | -extern struct dentry * lookup_one_len(const char *, struct dentry *, int); | |
85 | -extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int); | |
84 | +extern struct dentry *lookup_one_len(const char *, struct dentry *, int); | |
85 | +extern struct dentry *lookup_one_noperm(const char *, struct dentry *); | |
86 | 86 | |
87 | 87 | extern int follow_down(struct vfsmount **, struct dentry **); |
88 | 88 | extern int follow_up(struct vfsmount **, struct dentry **); |