diff options
| -rw-r--r-- | fs/namei.c | 72 | ||||
| -rw-r--r-- | fs/sysfs/group.c | 6 | ||||
| -rw-r--r-- | include/linux/namei.h | 1 |
3 files changed, 57 insertions, 22 deletions
diff --git a/fs/namei.c b/fs/namei.c index ee60cc4d3453..880052cadbcd 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
| 1243 | return err; | 1243 | return err; |
| 1244 | } | 1244 | } |
| 1245 | 1245 | ||
| 1246 | /* | 1246 | static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) |
| 1247 | * Restricted form of lookup. Doesn't follow links, single-component only, | ||
| 1248 | * needs parent already locked. Doesn't follow mounts. | ||
| 1249 | * SMP-safe. | ||
| 1250 | */ | ||
| 1251 | static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd) | ||
| 1252 | { | 1247 | { |
| 1253 | struct dentry * dentry; | 1248 | struct dentry *dentry; |
| 1254 | struct inode *inode; | 1249 | struct inode *inode; |
| 1255 | int err; | 1250 | int err; |
| 1256 | 1251 | ||
| 1257 | inode = base->d_inode; | 1252 | inode = base->d_inode; |
| 1258 | err = permission(inode, MAY_EXEC, nd); | ||
| 1259 | dentry = ERR_PTR(err); | ||
| 1260 | if (err) | ||
| 1261 | goto out; | ||
| 1262 | 1253 | ||
| 1263 | /* | 1254 | /* |
| 1264 | * See if the low-level filesystem might want | 1255 | * See if the low-level filesystem might want |
| @@ -1287,35 +1278,76 @@ out: | |||
| 1287 | return dentry; | 1278 | return dentry; |
| 1288 | } | 1279 | } |
| 1289 | 1280 | ||
| 1281 | /* | ||
| 1282 | * Restricted form of lookup. Doesn't follow links, single-component only, | ||
| 1283 | * needs parent already locked. Doesn't follow mounts. | ||
| 1284 | * SMP-safe. | ||
| 1285 | */ | ||
| 1286 | static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) | ||
| 1287 | { | ||
| 1288 | struct dentry *dentry; | ||
| 1289 | struct inode *inode; | ||
| 1290 | int err; | ||
| 1291 | |||
| 1292 | inode = base->d_inode; | ||
| 1293 | |||
| 1294 | err = permission(inode, MAY_EXEC, nd); | ||
| 1295 | dentry = ERR_PTR(err); | ||
| 1296 | if (err) | ||
| 1297 | goto out; | ||
| 1298 | |||
| 1299 | dentry = __lookup_hash_kern(name, base, nd); | ||
| 1300 | out: | ||
| 1301 | return dentry; | ||
| 1302 | } | ||
| 1303 | |||
| 1290 | static struct dentry *lookup_hash(struct nameidata *nd) | 1304 | static struct dentry *lookup_hash(struct nameidata *nd) |
| 1291 | { | 1305 | { |
| 1292 | return __lookup_hash(&nd->last, nd->dentry, nd); | 1306 | return __lookup_hash(&nd->last, nd->dentry, nd); |
| 1293 | } | 1307 | } |
| 1294 | 1308 | ||
| 1295 | /* SMP-safe */ | 1309 | /* SMP-safe */ |
| 1296 | struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) | 1310 | static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) |
| 1297 | { | 1311 | { |
| 1298 | unsigned long hash; | 1312 | unsigned long hash; |
| 1299 | struct qstr this; | ||
| 1300 | unsigned int c; | 1313 | unsigned int c; |
| 1301 | 1314 | ||
| 1302 | this.name = name; | 1315 | this->name = name; |
| 1303 | this.len = len; | 1316 | this->len = len; |
| 1304 | if (!len) | 1317 | if (!len) |
| 1305 | goto access; | 1318 | return -EACCES; |
| 1306 | 1319 | ||
| 1307 | hash = init_name_hash(); | 1320 | hash = init_name_hash(); |
| 1308 | while (len--) { | 1321 | while (len--) { |
| 1309 | c = *(const unsigned char *)name++; | 1322 | c = *(const unsigned char *)name++; |
| 1310 | if (c == '/' || c == '\0') | 1323 | if (c == '/' || c == '\0') |
| 1311 | goto access; | 1324 | return -EACCES; |
| 1312 | hash = partial_name_hash(c, hash); | 1325 | hash = partial_name_hash(c, hash); |
| 1313 | } | 1326 | } |
| 1314 | this.hash = end_name_hash(hash); | 1327 | this->hash = end_name_hash(hash); |
| 1328 | return 0; | ||
| 1329 | } | ||
| 1315 | 1330 | ||
| 1331 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | ||
| 1332 | { | ||
| 1333 | int err; | ||
| 1334 | struct qstr this; | ||
| 1335 | |||
| 1336 | err = __lookup_one_len(name, &this, base, len); | ||
| 1337 | if (err) | ||
| 1338 | return ERR_PTR(err); | ||
| 1316 | return __lookup_hash(&this, base, NULL); | 1339 | return __lookup_hash(&this, base, NULL); |
| 1317 | access: | 1340 | } |
| 1318 | return ERR_PTR(-EACCES); | 1341 | |
| 1342 | struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) | ||
| 1343 | { | ||
| 1344 | int err; | ||
| 1345 | struct qstr this; | ||
| 1346 | |||
| 1347 | err = __lookup_one_len(name, &this, base, len); | ||
| 1348 | if (err) | ||
| 1349 | return ERR_PTR(err); | ||
| 1350 | return __lookup_hash_kern(&this, base, NULL); | ||
| 1319 | } | 1351 | } |
| 1320 | 1352 | ||
| 1321 | /* | 1353 | /* |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index b20951c93761..52eed2a7a5ef 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
| @@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj, | |||
| 70 | { | 70 | { |
| 71 | struct dentry * dir; | 71 | struct dentry * dir; |
| 72 | 72 | ||
| 73 | if (grp->name) | 73 | if (grp->name) { |
| 74 | dir = lookup_one_len(grp->name, kobj->dentry, | 74 | dir = lookup_one_len_kern(grp->name, kobj->dentry, |
| 75 | strlen(grp->name)); | 75 | strlen(grp->name)); |
| 76 | BUG_ON(IS_ERR(dir)); | ||
| 77 | } | ||
| 76 | else | 78 | else |
| 77 | dir = dget(kobj->dentry); | 79 | dir = dget(kobj->dentry); |
| 78 | 80 | ||
diff --git a/include/linux/namei.h b/include/linux/namei.h index d39a5a67e979..b7dd24917f0d 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
| @@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); | |||
| 82 | extern void release_open_intent(struct nameidata *); | 82 | extern void release_open_intent(struct nameidata *); |
| 83 | 83 | ||
| 84 | extern struct dentry * lookup_one_len(const char *, struct dentry *, int); | 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); | ||
| 85 | 86 | ||
| 86 | extern int follow_down(struct vfsmount **, struct dentry **); | 87 | extern int follow_down(struct vfsmount **, struct dentry **); |
| 87 | extern int follow_up(struct vfsmount **, struct dentry **); | 88 | extern int follow_up(struct vfsmount **, struct dentry **); |
