diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 15:48:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 15:48:05 -0400 |
commit | fd3b36d275660c905da9900b078eea341847d5e4 (patch) | |
tree | 687872bfb4e3dce727d6bab3e8799cd67d4d5108 | |
parent | 8ea4a5d84e6c44b3508599fe114ea806e63985a4 (diff) | |
parent | 30ce4d1903e1d8a7ccd110860a5eef3c638ed8be (diff) |
Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs namei updates from Al Viro:
- make lookup_one_len() safe with parent locked only shared(incoming
afs series wants that)
- fix of getname_kernel() regression from 2015 (-stable fodder, that
one).
* 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
getname_kernel() needs to make sure that ->name != ->iname in long case
make lookup_one_len() safe to use with directory locked shared
new helper: __lookup_slow()
merge common parts of lookup_one_len{,_unlocked} into common helper
-rw-r--r-- | fs/namei.c | 124 |
1 files changed, 57 insertions, 67 deletions
diff --git a/fs/namei.c b/fs/namei.c index a66ed5a1622a..186bd2464fd5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -224,9 +224,10 @@ getname_kernel(const char * filename) | |||
224 | if (len <= EMBEDDED_NAME_MAX) { | 224 | if (len <= EMBEDDED_NAME_MAX) { |
225 | result->name = (char *)result->iname; | 225 | result->name = (char *)result->iname; |
226 | } else if (len <= PATH_MAX) { | 226 | } else if (len <= PATH_MAX) { |
227 | const size_t size = offsetof(struct filename, iname[1]); | ||
227 | struct filename *tmp; | 228 | struct filename *tmp; |
228 | 229 | ||
229 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | 230 | tmp = kmalloc(size, GFP_KERNEL); |
230 | if (unlikely(!tmp)) { | 231 | if (unlikely(!tmp)) { |
231 | __putname(result); | 232 | __putname(result); |
232 | return ERR_PTR(-ENOMEM); | 233 | return ERR_PTR(-ENOMEM); |
@@ -1597,22 +1598,21 @@ static int lookup_fast(struct nameidata *nd, | |||
1597 | } | 1598 | } |
1598 | 1599 | ||
1599 | /* Fast lookup failed, do it the slow way */ | 1600 | /* Fast lookup failed, do it the slow way */ |
1600 | static struct dentry *lookup_slow(const struct qstr *name, | 1601 | static struct dentry *__lookup_slow(const struct qstr *name, |
1601 | struct dentry *dir, | 1602 | struct dentry *dir, |
1602 | unsigned int flags) | 1603 | unsigned int flags) |
1603 | { | 1604 | { |
1604 | struct dentry *dentry = ERR_PTR(-ENOENT), *old; | 1605 | struct dentry *dentry, *old; |
1605 | struct inode *inode = dir->d_inode; | 1606 | struct inode *inode = dir->d_inode; |
1606 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); | 1607 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); |
1607 | 1608 | ||
1608 | inode_lock_shared(inode); | ||
1609 | /* Don't go there if it's already dead */ | 1609 | /* Don't go there if it's already dead */ |
1610 | if (unlikely(IS_DEADDIR(inode))) | 1610 | if (unlikely(IS_DEADDIR(inode))) |
1611 | goto out; | 1611 | return ERR_PTR(-ENOENT); |
1612 | again: | 1612 | again: |
1613 | dentry = d_alloc_parallel(dir, name, &wq); | 1613 | dentry = d_alloc_parallel(dir, name, &wq); |
1614 | if (IS_ERR(dentry)) | 1614 | if (IS_ERR(dentry)) |
1615 | goto out; | 1615 | return dentry; |
1616 | if (unlikely(!d_in_lookup(dentry))) { | 1616 | if (unlikely(!d_in_lookup(dentry))) { |
1617 | if (!(flags & LOOKUP_NO_REVAL)) { | 1617 | if (!(flags & LOOKUP_NO_REVAL)) { |
1618 | int error = d_revalidate(dentry, flags); | 1618 | int error = d_revalidate(dentry, flags); |
@@ -1634,11 +1634,21 @@ again: | |||
1634 | dentry = old; | 1634 | dentry = old; |
1635 | } | 1635 | } |
1636 | } | 1636 | } |
1637 | out: | ||
1638 | inode_unlock_shared(inode); | ||
1639 | return dentry; | 1637 | return dentry; |
1640 | } | 1638 | } |
1641 | 1639 | ||
1640 | static struct dentry *lookup_slow(const struct qstr *name, | ||
1641 | struct dentry *dir, | ||
1642 | unsigned int flags) | ||
1643 | { | ||
1644 | struct inode *inode = dir->d_inode; | ||
1645 | struct dentry *res; | ||
1646 | inode_lock_shared(inode); | ||
1647 | res = __lookup_slow(name, dir, flags); | ||
1648 | inode_unlock_shared(inode); | ||
1649 | return res; | ||
1650 | } | ||
1651 | |||
1642 | static inline int may_lookup(struct nameidata *nd) | 1652 | static inline int may_lookup(struct nameidata *nd) |
1643 | { | 1653 | { |
1644 | if (nd->flags & LOOKUP_RCU) { | 1654 | if (nd->flags & LOOKUP_RCU) { |
@@ -2421,56 +2431,63 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
2421 | } | 2431 | } |
2422 | EXPORT_SYMBOL(vfs_path_lookup); | 2432 | EXPORT_SYMBOL(vfs_path_lookup); |
2423 | 2433 | ||
2424 | /** | 2434 | static int lookup_one_len_common(const char *name, struct dentry *base, |
2425 | * lookup_one_len - filesystem helper to lookup single pathname component | 2435 | int len, struct qstr *this) |
2426 | * @name: pathname component to lookup | ||
2427 | * @base: base directory to lookup from | ||
2428 | * @len: maximum length @len should be interpreted to | ||
2429 | * | ||
2430 | * Note that this routine is purely a helper for filesystem usage and should | ||
2431 | * not be called by generic code. | ||
2432 | * | ||
2433 | * The caller must hold base->i_mutex. | ||
2434 | */ | ||
2435 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | ||
2436 | { | 2436 | { |
2437 | struct qstr this; | 2437 | this->name = name; |
2438 | unsigned int c; | 2438 | this->len = len; |
2439 | int err; | 2439 | this->hash = full_name_hash(base, name, len); |
2440 | |||
2441 | WARN_ON_ONCE(!inode_is_locked(base->d_inode)); | ||
2442 | |||
2443 | this.name = name; | ||
2444 | this.len = len; | ||
2445 | this.hash = full_name_hash(base, name, len); | ||
2446 | if (!len) | 2440 | if (!len) |
2447 | return ERR_PTR(-EACCES); | 2441 | return -EACCES; |
2448 | 2442 | ||
2449 | if (unlikely(name[0] == '.')) { | 2443 | if (unlikely(name[0] == '.')) { |
2450 | if (len < 2 || (len == 2 && name[1] == '.')) | 2444 | if (len < 2 || (len == 2 && name[1] == '.')) |
2451 | return ERR_PTR(-EACCES); | 2445 | return -EACCES; |
2452 | } | 2446 | } |
2453 | 2447 | ||
2454 | while (len--) { | 2448 | while (len--) { |
2455 | c = *(const unsigned char *)name++; | 2449 | unsigned int c = *(const unsigned char *)name++; |
2456 | if (c == '/' || c == '\0') | 2450 | if (c == '/' || c == '\0') |
2457 | return ERR_PTR(-EACCES); | 2451 | return -EACCES; |
2458 | } | 2452 | } |
2459 | /* | 2453 | /* |
2460 | * See if the low-level filesystem might want | 2454 | * See if the low-level filesystem might want |
2461 | * to use its own hash.. | 2455 | * to use its own hash.. |
2462 | */ | 2456 | */ |
2463 | if (base->d_flags & DCACHE_OP_HASH) { | 2457 | if (base->d_flags & DCACHE_OP_HASH) { |
2464 | int err = base->d_op->d_hash(base, &this); | 2458 | int err = base->d_op->d_hash(base, this); |
2465 | if (err < 0) | 2459 | if (err < 0) |
2466 | return ERR_PTR(err); | 2460 | return err; |
2467 | } | 2461 | } |
2468 | 2462 | ||
2469 | err = inode_permission(base->d_inode, MAY_EXEC); | 2463 | return inode_permission(base->d_inode, MAY_EXEC); |
2464 | } | ||
2465 | |||
2466 | /** | ||
2467 | * lookup_one_len - filesystem helper to lookup single pathname component | ||
2468 | * @name: pathname component to lookup | ||
2469 | * @base: base directory to lookup from | ||
2470 | * @len: maximum length @len should be interpreted to | ||
2471 | * | ||
2472 | * Note that this routine is purely a helper for filesystem usage and should | ||
2473 | * not be called by generic code. | ||
2474 | * | ||
2475 | * The caller must hold base->i_mutex. | ||
2476 | */ | ||
2477 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | ||
2478 | { | ||
2479 | struct dentry *dentry; | ||
2480 | struct qstr this; | ||
2481 | int err; | ||
2482 | |||
2483 | WARN_ON_ONCE(!inode_is_locked(base->d_inode)); | ||
2484 | |||
2485 | err = lookup_one_len_common(name, base, len, &this); | ||
2470 | if (err) | 2486 | if (err) |
2471 | return ERR_PTR(err); | 2487 | return ERR_PTR(err); |
2472 | 2488 | ||
2473 | return __lookup_hash(&this, base, 0); | 2489 | dentry = lookup_dcache(&this, base, 0); |
2490 | return dentry ? dentry : __lookup_slow(&this, base, 0); | ||
2474 | } | 2491 | } |
2475 | EXPORT_SYMBOL(lookup_one_len); | 2492 | EXPORT_SYMBOL(lookup_one_len); |
2476 | 2493 | ||
@@ -2490,37 +2507,10 @@ struct dentry *lookup_one_len_unlocked(const char *name, | |||
2490 | struct dentry *base, int len) | 2507 | struct dentry *base, int len) |
2491 | { | 2508 | { |
2492 | struct qstr this; | 2509 | struct qstr this; |
2493 | unsigned int c; | ||
2494 | int err; | 2510 | int err; |
2495 | struct dentry *ret; | 2511 | struct dentry *ret; |
2496 | 2512 | ||
2497 | this.name = name; | 2513 | err = lookup_one_len_common(name, base, len, &this); |
2498 | this.len = len; | ||
2499 | this.hash = full_name_hash(base, name, len); | ||
2500 | if (!len) | ||
2501 | return ERR_PTR(-EACCES); | ||
2502 | |||
2503 | if (unlikely(name[0] == '.')) { | ||
2504 | if (len < 2 || (len == 2 && name[1] == '.')) | ||
2505 | return ERR_PTR(-EACCES); | ||
2506 | } | ||
2507 | |||
2508 | while (len--) { | ||
2509 | c = *(const unsigned char *)name++; | ||
2510 | if (c == '/' || c == '\0') | ||
2511 | return ERR_PTR(-EACCES); | ||
2512 | } | ||
2513 | /* | ||
2514 | * See if the low-level filesystem might want | ||
2515 | * to use its own hash.. | ||
2516 | */ | ||
2517 | if (base->d_flags & DCACHE_OP_HASH) { | ||
2518 | int err = base->d_op->d_hash(base, &this); | ||
2519 | if (err < 0) | ||
2520 | return ERR_PTR(err); | ||
2521 | } | ||
2522 | |||
2523 | err = inode_permission(base->d_inode, MAY_EXEC); | ||
2524 | if (err) | 2514 | if (err) |
2525 | return ERR_PTR(err); | 2515 | return ERR_PTR(err); |
2526 | 2516 | ||