diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namei.c | 72 | ||||
-rw-r--r-- | fs/sysfs/group.c | 6 |
2 files changed, 56 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 | ||