diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-02 07:16:16 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-10 22:20:01 -0400 |
| commit | 894bc8c4662ba9daceafe943a5ba0dd407da5cd3 (patch) | |
| tree | 88b22172306c162df0a5fc7adbc208e3fd535bd5 /fs/namei.c | |
| parent | 3b2e7f7539bdf5650bf5e13f18c883b7b008d03b (diff) | |
namei: remove restrictions on nesting depth
The only restriction is that on the total amount of symlinks
crossed; how they are nested does not matter
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/fs/namei.c b/fs/namei.c index e5715a567860..1ae34cd0d590 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -492,6 +492,7 @@ void path_put(const struct path *path) | |||
| 492 | } | 492 | } |
| 493 | EXPORT_SYMBOL(path_put); | 493 | EXPORT_SYMBOL(path_put); |
| 494 | 494 | ||
| 495 | #define EMBEDDED_LEVELS 2 | ||
| 495 | struct nameidata { | 496 | struct nameidata { |
| 496 | struct path path; | 497 | struct path path; |
| 497 | union { | 498 | union { |
| @@ -509,9 +510,42 @@ struct nameidata { | |||
| 509 | struct path link; | 510 | struct path link; |
| 510 | void *cookie; | 511 | void *cookie; |
| 511 | const char *name; | 512 | const char *name; |
| 512 | } stack[MAX_NESTED_LINKS + 1]; | 513 | } *stack, internal[EMBEDDED_LEVELS]; |
| 513 | }; | 514 | }; |
| 514 | 515 | ||
| 516 | static void set_nameidata(struct nameidata *nd) | ||
| 517 | { | ||
| 518 | nd->stack = nd->internal; | ||
| 519 | } | ||
| 520 | |||
| 521 | static void restore_nameidata(struct nameidata *nd) | ||
| 522 | { | ||
| 523 | if (nd->stack != nd->internal) { | ||
| 524 | kfree(nd->stack); | ||
| 525 | nd->stack = nd->internal; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | static int __nd_alloc_stack(struct nameidata *nd) | ||
| 530 | { | ||
| 531 | struct saved *p = kmalloc((MAXSYMLINKS + 1) * sizeof(struct saved), | ||
| 532 | GFP_KERNEL); | ||
| 533 | if (unlikely(!p)) | ||
| 534 | return -ENOMEM; | ||
| 535 | memcpy(p, nd->internal, sizeof(nd->internal)); | ||
| 536 | nd->stack = p; | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | static inline int nd_alloc_stack(struct nameidata *nd) | ||
| 541 | { | ||
| 542 | if (likely(nd->depth != EMBEDDED_LEVELS - 1)) | ||
| 543 | return 0; | ||
| 544 | if (likely(nd->stack != nd->internal)) | ||
| 545 | return 0; | ||
| 546 | return __nd_alloc_stack(nd); | ||
| 547 | } | ||
| 548 | |||
| 515 | /* | 549 | /* |
| 516 | * Path walking has 2 modes, rcu-walk and ref-walk (see | 550 | * Path walking has 2 modes, rcu-walk and ref-walk (see |
| 517 | * Documentation/filesystems/path-lookup.txt). In situations when we can't | 551 | * Documentation/filesystems/path-lookup.txt). In situations when we can't |
| @@ -857,7 +891,7 @@ const char *get_link(struct nameidata *nd) | |||
| 857 | if (nd->link.mnt == nd->path.mnt) | 891 | if (nd->link.mnt == nd->path.mnt) |
| 858 | mntget(nd->link.mnt); | 892 | mntget(nd->link.mnt); |
| 859 | 893 | ||
| 860 | if (unlikely(current->total_link_count >= 40)) { | 894 | if (unlikely(current->total_link_count >= MAXSYMLINKS)) { |
| 861 | path_put(&nd->path); | 895 | path_put(&nd->path); |
| 862 | path_put(&nd->link); | 896 | path_put(&nd->link); |
| 863 | return ERR_PTR(-ELOOP); | 897 | return ERR_PTR(-ELOOP); |
| @@ -1789,22 +1823,18 @@ Walked: | |||
| 1789 | if (err) { | 1823 | if (err) { |
| 1790 | const char *s; | 1824 | const char *s; |
| 1791 | 1825 | ||
| 1792 | if (unlikely(current->link_count >= MAX_NESTED_LINKS)) { | 1826 | err = nd_alloc_stack(nd); |
| 1793 | path_put_conditional(&nd->link, nd); | 1827 | if (unlikely(err)) { |
| 1794 | path_put(&nd->path); | 1828 | path_to_nameidata(&nd->link, nd); |
| 1795 | err = -ELOOP; | 1829 | break; |
| 1796 | goto Err; | ||
| 1797 | } | 1830 | } |
| 1798 | BUG_ON(nd->depth >= MAX_NESTED_LINKS); | ||
| 1799 | 1831 | ||
| 1800 | nd->depth++; | 1832 | nd->depth++; |
| 1801 | current->link_count++; | ||
| 1802 | 1833 | ||
| 1803 | s = get_link(nd); | 1834 | s = get_link(nd); |
| 1804 | 1835 | ||
| 1805 | if (unlikely(IS_ERR(s))) { | 1836 | if (unlikely(IS_ERR(s))) { |
| 1806 | err = PTR_ERR(s); | 1837 | err = PTR_ERR(s); |
| 1807 | current->link_count--; | ||
| 1808 | nd->depth--; | 1838 | nd->depth--; |
| 1809 | goto Err; | 1839 | goto Err; |
| 1810 | } | 1840 | } |
| @@ -1812,7 +1842,6 @@ Walked: | |||
| 1812 | if (unlikely(!s)) { | 1842 | if (unlikely(!s)) { |
| 1813 | /* jumped */ | 1843 | /* jumped */ |
| 1814 | put_link(nd); | 1844 | put_link(nd); |
| 1815 | current->link_count--; | ||
| 1816 | nd->depth--; | 1845 | nd->depth--; |
| 1817 | } else { | 1846 | } else { |
| 1818 | if (*s == '/') { | 1847 | if (*s == '/') { |
| @@ -1842,7 +1871,6 @@ Walked: | |||
| 1842 | Err: | 1871 | Err: |
| 1843 | while (unlikely(nd->depth)) { | 1872 | while (unlikely(nd->depth)) { |
| 1844 | put_link(nd); | 1873 | put_link(nd); |
| 1845 | current->link_count--; | ||
| 1846 | nd->depth--; | 1874 | nd->depth--; |
| 1847 | } | 1875 | } |
| 1848 | return err; | 1876 | return err; |
| @@ -1851,7 +1879,6 @@ OK: | |||
| 1851 | name = nd->stack[nd->depth].name; | 1879 | name = nd->stack[nd->depth].name; |
| 1852 | err = walk_component(nd, LOOKUP_FOLLOW); | 1880 | err = walk_component(nd, LOOKUP_FOLLOW); |
| 1853 | put_link(nd); | 1881 | put_link(nd); |
| 1854 | current->link_count--; | ||
| 1855 | nd->depth--; | 1882 | nd->depth--; |
| 1856 | goto Walked; | 1883 | goto Walked; |
| 1857 | } | 1884 | } |
| @@ -2055,7 +2082,11 @@ static int path_lookupat(int dfd, const struct filename *name, | |||
| 2055 | static int filename_lookup(int dfd, struct filename *name, | 2082 | static int filename_lookup(int dfd, struct filename *name, |
| 2056 | unsigned int flags, struct nameidata *nd) | 2083 | unsigned int flags, struct nameidata *nd) |
| 2057 | { | 2084 | { |
| 2058 | int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); | 2085 | int retval; |
| 2086 | |||
| 2087 | set_nameidata(nd); | ||
| 2088 | retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); | ||
| 2089 | |||
| 2059 | if (unlikely(retval == -ECHILD)) | 2090 | if (unlikely(retval == -ECHILD)) |
| 2060 | retval = path_lookupat(dfd, name, flags, nd); | 2091 | retval = path_lookupat(dfd, name, flags, nd); |
| 2061 | if (unlikely(retval == -ESTALE)) | 2092 | if (unlikely(retval == -ESTALE)) |
| @@ -2063,6 +2094,7 @@ static int filename_lookup(int dfd, struct filename *name, | |||
| 2063 | 2094 | ||
| 2064 | if (likely(!retval)) | 2095 | if (likely(!retval)) |
| 2065 | audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); | 2096 | audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); |
| 2097 | restore_nameidata(nd); | ||
| 2066 | return retval; | 2098 | return retval; |
| 2067 | } | 2099 | } |
| 2068 | 2100 | ||
| @@ -2393,6 +2425,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path, | |||
| 2393 | int error; | 2425 | int error; |
| 2394 | if (IS_ERR(name)) | 2426 | if (IS_ERR(name)) |
| 2395 | return PTR_ERR(name); | 2427 | return PTR_ERR(name); |
| 2428 | set_nameidata(&nd); | ||
| 2396 | error = path_mountpoint(dfd, name, path, &nd, flags | LOOKUP_RCU); | 2429 | error = path_mountpoint(dfd, name, path, &nd, flags | LOOKUP_RCU); |
| 2397 | if (unlikely(error == -ECHILD)) | 2430 | if (unlikely(error == -ECHILD)) |
| 2398 | error = path_mountpoint(dfd, name, path, &nd, flags); | 2431 | error = path_mountpoint(dfd, name, path, &nd, flags); |
| @@ -2400,6 +2433,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path, | |||
| 2400 | error = path_mountpoint(dfd, name, path, &nd, flags | LOOKUP_REVAL); | 2433 | error = path_mountpoint(dfd, name, path, &nd, flags | LOOKUP_REVAL); |
| 2401 | if (likely(!error)) | 2434 | if (likely(!error)) |
| 2402 | audit_inode(name, path->dentry, 0); | 2435 | audit_inode(name, path->dentry, 0); |
| 2436 | restore_nameidata(&nd); | ||
| 2403 | putname(name); | 2437 | putname(name); |
| 2404 | return error; | 2438 | return error; |
| 2405 | } | 2439 | } |
| @@ -3288,11 +3322,13 @@ struct file *do_filp_open(int dfd, struct filename *pathname, | |||
| 3288 | int flags = op->lookup_flags; | 3322 | int flags = op->lookup_flags; |
| 3289 | struct file *filp; | 3323 | struct file *filp; |
| 3290 | 3324 | ||
| 3325 | set_nameidata(&nd); | ||
| 3291 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); | 3326 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); |
| 3292 | if (unlikely(filp == ERR_PTR(-ECHILD))) | 3327 | if (unlikely(filp == ERR_PTR(-ECHILD))) |
| 3293 | filp = path_openat(dfd, pathname, &nd, op, flags); | 3328 | filp = path_openat(dfd, pathname, &nd, op, flags); |
| 3294 | if (unlikely(filp == ERR_PTR(-ESTALE))) | 3329 | if (unlikely(filp == ERR_PTR(-ESTALE))) |
| 3295 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL); | 3330 | filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL); |
| 3331 | restore_nameidata(&nd); | ||
| 3296 | return filp; | 3332 | return filp; |
| 3297 | } | 3333 | } |
| 3298 | 3334 | ||
| @@ -3306,6 +3342,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
| 3306 | 3342 | ||
| 3307 | nd.root.mnt = mnt; | 3343 | nd.root.mnt = mnt; |
| 3308 | nd.root.dentry = dentry; | 3344 | nd.root.dentry = dentry; |
| 3345 | set_nameidata(&nd); | ||
| 3309 | 3346 | ||
| 3310 | if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) | 3347 | if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) |
| 3311 | return ERR_PTR(-ELOOP); | 3348 | return ERR_PTR(-ELOOP); |
| @@ -3319,6 +3356,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
| 3319 | file = path_openat(-1, filename, &nd, op, flags); | 3356 | file = path_openat(-1, filename, &nd, op, flags); |
| 3320 | if (unlikely(file == ERR_PTR(-ESTALE))) | 3357 | if (unlikely(file == ERR_PTR(-ESTALE))) |
| 3321 | file = path_openat(-1, filename, &nd, op, flags | LOOKUP_REVAL); | 3358 | file = path_openat(-1, filename, &nd, op, flags | LOOKUP_REVAL); |
| 3359 | restore_nameidata(&nd); | ||
| 3322 | putname(filename); | 3360 | putname(filename); |
| 3323 | return file; | 3361 | return file; |
| 3324 | } | 3362 | } |
