diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 176 |
1 files changed, 87 insertions, 89 deletions
diff --git a/fs/namei.c b/fs/namei.c index c83145af4bfc..ffab2e06e147 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -119,15 +119,14 @@ | |||
119 | * PATH_MAX includes the nul terminator --RR. | 119 | * PATH_MAX includes the nul terminator --RR. |
120 | */ | 120 | */ |
121 | 121 | ||
122 | #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) | 122 | #define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) |
123 | 123 | ||
124 | struct filename * | 124 | struct filename * |
125 | getname_flags(const char __user *filename, int flags, int *empty) | 125 | getname_flags(const char __user *filename, int flags, int *empty) |
126 | { | 126 | { |
127 | struct filename *result, *err; | 127 | struct filename *result; |
128 | int len; | ||
129 | long max; | ||
130 | char *kname; | 128 | char *kname; |
129 | int len; | ||
131 | 130 | ||
132 | result = audit_reusename(filename); | 131 | result = audit_reusename(filename); |
133 | if (result) | 132 | if (result) |
@@ -136,22 +135,18 @@ getname_flags(const char __user *filename, int flags, int *empty) | |||
136 | result = __getname(); | 135 | result = __getname(); |
137 | if (unlikely(!result)) | 136 | if (unlikely(!result)) |
138 | return ERR_PTR(-ENOMEM); | 137 | return ERR_PTR(-ENOMEM); |
139 | result->refcnt = 1; | ||
140 | 138 | ||
141 | /* | 139 | /* |
142 | * First, try to embed the struct filename inside the names_cache | 140 | * First, try to embed the struct filename inside the names_cache |
143 | * allocation | 141 | * allocation |
144 | */ | 142 | */ |
145 | kname = (char *)result + sizeof(*result); | 143 | kname = (char *)result->iname; |
146 | result->name = kname; | 144 | result->name = kname; |
147 | result->separate = false; | ||
148 | max = EMBEDDED_NAME_MAX; | ||
149 | 145 | ||
150 | recopy: | 146 | len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); |
151 | len = strncpy_from_user(kname, filename, max); | ||
152 | if (unlikely(len < 0)) { | 147 | if (unlikely(len < 0)) { |
153 | err = ERR_PTR(len); | 148 | __putname(result); |
154 | goto error; | 149 | return ERR_PTR(len); |
155 | } | 150 | } |
156 | 151 | ||
157 | /* | 152 | /* |
@@ -160,43 +155,49 @@ recopy: | |||
160 | * names_cache allocation for the pathname, and re-do the copy from | 155 | * names_cache allocation for the pathname, and re-do the copy from |
161 | * userland. | 156 | * userland. |
162 | */ | 157 | */ |
163 | if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) { | 158 | if (unlikely(len == EMBEDDED_NAME_MAX)) { |
159 | const size_t size = offsetof(struct filename, iname[1]); | ||
164 | kname = (char *)result; | 160 | kname = (char *)result; |
165 | 161 | ||
166 | result = kzalloc(sizeof(*result), GFP_KERNEL); | 162 | /* |
167 | if (!result) { | 163 | * size is chosen that way we to guarantee that |
168 | err = ERR_PTR(-ENOMEM); | 164 | * result->iname[0] is within the same object and that |
169 | result = (struct filename *)kname; | 165 | * kname can't be equal to result->iname, no matter what. |
170 | goto error; | 166 | */ |
167 | result = kzalloc(size, GFP_KERNEL); | ||
168 | if (unlikely(!result)) { | ||
169 | __putname(kname); | ||
170 | return ERR_PTR(-ENOMEM); | ||
171 | } | 171 | } |
172 | result->name = kname; | 172 | result->name = kname; |
173 | result->separate = true; | 173 | len = strncpy_from_user(kname, filename, PATH_MAX); |
174 | result->refcnt = 1; | 174 | if (unlikely(len < 0)) { |
175 | max = PATH_MAX; | 175 | __putname(kname); |
176 | goto recopy; | 176 | kfree(result); |
177 | return ERR_PTR(len); | ||
178 | } | ||
179 | if (unlikely(len == PATH_MAX)) { | ||
180 | __putname(kname); | ||
181 | kfree(result); | ||
182 | return ERR_PTR(-ENAMETOOLONG); | ||
183 | } | ||
177 | } | 184 | } |
178 | 185 | ||
186 | result->refcnt = 1; | ||
179 | /* The empty path is special. */ | 187 | /* The empty path is special. */ |
180 | if (unlikely(!len)) { | 188 | if (unlikely(!len)) { |
181 | if (empty) | 189 | if (empty) |
182 | *empty = 1; | 190 | *empty = 1; |
183 | err = ERR_PTR(-ENOENT); | 191 | if (!(flags & LOOKUP_EMPTY)) { |
184 | if (!(flags & LOOKUP_EMPTY)) | 192 | putname(result); |
185 | goto error; | 193 | return ERR_PTR(-ENOENT); |
194 | } | ||
186 | } | 195 | } |
187 | 196 | ||
188 | err = ERR_PTR(-ENAMETOOLONG); | ||
189 | if (unlikely(len >= PATH_MAX)) | ||
190 | goto error; | ||
191 | |||
192 | result->uptr = filename; | 197 | result->uptr = filename; |
193 | result->aname = NULL; | 198 | result->aname = NULL; |
194 | audit_getname(result); | 199 | audit_getname(result); |
195 | return result; | 200 | return result; |
196 | |||
197 | error: | ||
198 | putname(result); | ||
199 | return err; | ||
200 | } | 201 | } |
201 | 202 | ||
202 | struct filename * | 203 | struct filename * |
@@ -216,8 +217,7 @@ getname_kernel(const char * filename) | |||
216 | return ERR_PTR(-ENOMEM); | 217 | return ERR_PTR(-ENOMEM); |
217 | 218 | ||
218 | if (len <= EMBEDDED_NAME_MAX) { | 219 | if (len <= EMBEDDED_NAME_MAX) { |
219 | result->name = (char *)(result) + sizeof(*result); | 220 | result->name = (char *)result->iname; |
220 | result->separate = false; | ||
221 | } else if (len <= PATH_MAX) { | 221 | } else if (len <= PATH_MAX) { |
222 | struct filename *tmp; | 222 | struct filename *tmp; |
223 | 223 | ||
@@ -227,7 +227,6 @@ getname_kernel(const char * filename) | |||
227 | return ERR_PTR(-ENOMEM); | 227 | return ERR_PTR(-ENOMEM); |
228 | } | 228 | } |
229 | tmp->name = (char *)result; | 229 | tmp->name = (char *)result; |
230 | tmp->separate = true; | ||
231 | result = tmp; | 230 | result = tmp; |
232 | } else { | 231 | } else { |
233 | __putname(result); | 232 | __putname(result); |
@@ -249,7 +248,7 @@ void putname(struct filename *name) | |||
249 | if (--name->refcnt > 0) | 248 | if (--name->refcnt > 0) |
250 | return; | 249 | return; |
251 | 250 | ||
252 | if (name->separate) { | 251 | if (name->name != name->iname) { |
253 | __putname(name->name); | 252 | __putname(name->name); |
254 | kfree(name); | 253 | kfree(name); |
255 | } else | 254 | } else |
@@ -1586,7 +1585,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1586 | inode = path->dentry->d_inode; | 1585 | inode = path->dentry->d_inode; |
1587 | } | 1586 | } |
1588 | err = -ENOENT; | 1587 | err = -ENOENT; |
1589 | if (!inode || d_is_negative(path->dentry)) | 1588 | if (d_is_negative(path->dentry)) |
1590 | goto out_path_put; | 1589 | goto out_path_put; |
1591 | 1590 | ||
1592 | if (should_follow_link(path->dentry, follow)) { | 1591 | if (should_follow_link(path->dentry, follow)) { |
@@ -1851,10 +1850,11 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1851 | return err; | 1850 | return err; |
1852 | } | 1851 | } |
1853 | 1852 | ||
1854 | static int path_init(int dfd, const char *name, unsigned int flags, | 1853 | static int path_init(int dfd, const struct filename *name, unsigned int flags, |
1855 | struct nameidata *nd) | 1854 | struct nameidata *nd) |
1856 | { | 1855 | { |
1857 | int retval = 0; | 1856 | int retval = 0; |
1857 | const char *s = name->name; | ||
1858 | 1858 | ||
1859 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1859 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1860 | nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; | 1860 | nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; |
@@ -1863,7 +1863,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1863 | if (flags & LOOKUP_ROOT) { | 1863 | if (flags & LOOKUP_ROOT) { |
1864 | struct dentry *root = nd->root.dentry; | 1864 | struct dentry *root = nd->root.dentry; |
1865 | struct inode *inode = root->d_inode; | 1865 | struct inode *inode = root->d_inode; |
1866 | if (*name) { | 1866 | if (*s) { |
1867 | if (!d_can_lookup(root)) | 1867 | if (!d_can_lookup(root)) |
1868 | return -ENOTDIR; | 1868 | return -ENOTDIR; |
1869 | retval = inode_permission(inode, MAY_EXEC); | 1869 | retval = inode_permission(inode, MAY_EXEC); |
@@ -1885,7 +1885,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1885 | nd->root.mnt = NULL; | 1885 | nd->root.mnt = NULL; |
1886 | 1886 | ||
1887 | nd->m_seq = read_seqbegin(&mount_lock); | 1887 | nd->m_seq = read_seqbegin(&mount_lock); |
1888 | if (*name=='/') { | 1888 | if (*s == '/') { |
1889 | if (flags & LOOKUP_RCU) { | 1889 | if (flags & LOOKUP_RCU) { |
1890 | rcu_read_lock(); | 1890 | rcu_read_lock(); |
1891 | nd->seq = set_root_rcu(nd); | 1891 | nd->seq = set_root_rcu(nd); |
@@ -1919,7 +1919,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1919 | 1919 | ||
1920 | dentry = f.file->f_path.dentry; | 1920 | dentry = f.file->f_path.dentry; |
1921 | 1921 | ||
1922 | if (*name) { | 1922 | if (*s) { |
1923 | if (!d_can_lookup(dentry)) { | 1923 | if (!d_can_lookup(dentry)) { |
1924 | fdput(f); | 1924 | fdput(f); |
1925 | return -ENOTDIR; | 1925 | return -ENOTDIR; |
@@ -1949,7 +1949,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1949 | return -ECHILD; | 1949 | return -ECHILD; |
1950 | done: | 1950 | done: |
1951 | current->total_link_count = 0; | 1951 | current->total_link_count = 0; |
1952 | return link_path_walk(name, nd); | 1952 | return link_path_walk(s, nd); |
1953 | } | 1953 | } |
1954 | 1954 | ||
1955 | static void path_cleanup(struct nameidata *nd) | 1955 | static void path_cleanup(struct nameidata *nd) |
@@ -1972,7 +1972,7 @@ static inline int lookup_last(struct nameidata *nd, struct path *path) | |||
1972 | } | 1972 | } |
1973 | 1973 | ||
1974 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1974 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
1975 | static int path_lookupat(int dfd, const char *name, | 1975 | static int path_lookupat(int dfd, const struct filename *name, |
1976 | unsigned int flags, struct nameidata *nd) | 1976 | unsigned int flags, struct nameidata *nd) |
1977 | { | 1977 | { |
1978 | struct path path; | 1978 | struct path path; |
@@ -2027,31 +2027,17 @@ static int path_lookupat(int dfd, const char *name, | |||
2027 | static int filename_lookup(int dfd, struct filename *name, | 2027 | static int filename_lookup(int dfd, struct filename *name, |
2028 | unsigned int flags, struct nameidata *nd) | 2028 | unsigned int flags, struct nameidata *nd) |
2029 | { | 2029 | { |
2030 | int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd); | 2030 | int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); |
2031 | if (unlikely(retval == -ECHILD)) | 2031 | if (unlikely(retval == -ECHILD)) |
2032 | retval = path_lookupat(dfd, name->name, flags, nd); | 2032 | retval = path_lookupat(dfd, name, flags, nd); |
2033 | if (unlikely(retval == -ESTALE)) | 2033 | if (unlikely(retval == -ESTALE)) |
2034 | retval = path_lookupat(dfd, name->name, | 2034 | retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); |
2035 | flags | LOOKUP_REVAL, nd); | ||
2036 | 2035 | ||
2037 | if (likely(!retval)) | 2036 | if (likely(!retval)) |
2038 | audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); | 2037 | audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); |
2039 | return retval; | 2038 | return retval; |
2040 | } | 2039 | } |
2041 | 2040 | ||
2042 | static int do_path_lookup(int dfd, const char *name, | ||
2043 | unsigned int flags, struct nameidata *nd) | ||
2044 | { | ||
2045 | struct filename *filename = getname_kernel(name); | ||
2046 | int retval = PTR_ERR(filename); | ||
2047 | |||
2048 | if (!IS_ERR(filename)) { | ||
2049 | retval = filename_lookup(dfd, filename, flags, nd); | ||
2050 | putname(filename); | ||
2051 | } | ||
2052 | return retval; | ||
2053 | } | ||
2054 | |||
2055 | /* does lookup, returns the object with parent locked */ | 2041 | /* does lookup, returns the object with parent locked */ |
2056 | struct dentry *kern_path_locked(const char *name, struct path *path) | 2042 | struct dentry *kern_path_locked(const char *name, struct path *path) |
2057 | { | 2043 | { |
@@ -2089,9 +2075,15 @@ out: | |||
2089 | int kern_path(const char *name, unsigned int flags, struct path *path) | 2075 | int kern_path(const char *name, unsigned int flags, struct path *path) |
2090 | { | 2076 | { |
2091 | struct nameidata nd; | 2077 | struct nameidata nd; |
2092 | int res = do_path_lookup(AT_FDCWD, name, flags, &nd); | 2078 | struct filename *filename = getname_kernel(name); |
2093 | if (!res) | 2079 | int res = PTR_ERR(filename); |
2094 | *path = nd.path; | 2080 | |
2081 | if (!IS_ERR(filename)) { | ||
2082 | res = filename_lookup(AT_FDCWD, filename, flags, &nd); | ||
2083 | putname(filename); | ||
2084 | if (!res) | ||
2085 | *path = nd.path; | ||
2086 | } | ||
2095 | return res; | 2087 | return res; |
2096 | } | 2088 | } |
2097 | EXPORT_SYMBOL(kern_path); | 2089 | EXPORT_SYMBOL(kern_path); |
@@ -2108,15 +2100,22 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
2108 | const char *name, unsigned int flags, | 2100 | const char *name, unsigned int flags, |
2109 | struct path *path) | 2101 | struct path *path) |
2110 | { | 2102 | { |
2111 | struct nameidata nd; | 2103 | struct filename *filename = getname_kernel(name); |
2112 | int err; | 2104 | int err = PTR_ERR(filename); |
2113 | nd.root.dentry = dentry; | 2105 | |
2114 | nd.root.mnt = mnt; | ||
2115 | BUG_ON(flags & LOOKUP_PARENT); | 2106 | BUG_ON(flags & LOOKUP_PARENT); |
2116 | /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */ | 2107 | |
2117 | err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd); | 2108 | /* the first argument of filename_lookup() is ignored with LOOKUP_ROOT */ |
2118 | if (!err) | 2109 | if (!IS_ERR(filename)) { |
2119 | *path = nd.path; | 2110 | struct nameidata nd; |
2111 | nd.root.dentry = dentry; | ||
2112 | nd.root.mnt = mnt; | ||
2113 | err = filename_lookup(AT_FDCWD, filename, | ||
2114 | flags | LOOKUP_ROOT, &nd); | ||
2115 | if (!err) | ||
2116 | *path = nd.path; | ||
2117 | putname(filename); | ||
2118 | } | ||
2120 | return err; | 2119 | return err; |
2121 | } | 2120 | } |
2122 | EXPORT_SYMBOL(vfs_path_lookup); | 2121 | EXPORT_SYMBOL(vfs_path_lookup); |
@@ -2138,9 +2137,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) | |||
2138 | * @len: maximum length @len should be interpreted to | 2137 | * @len: maximum length @len should be interpreted to |
2139 | * | 2138 | * |
2140 | * Note that this routine is purely a helper for filesystem usage and should | 2139 | * Note that this routine is purely a helper for filesystem usage and should |
2141 | * not be called by generic code. Also note that by using this function the | 2140 | * not be called by generic code. |
2142 | * nameidata argument is passed to the filesystem methods and a filesystem | ||
2143 | * using this helper needs to be prepared for that. | ||
2144 | */ | 2141 | */ |
2145 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | 2142 | struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) |
2146 | { | 2143 | { |
@@ -2313,7 +2310,7 @@ mountpoint_last(struct nameidata *nd, struct path *path) | |||
2313 | mutex_unlock(&dir->d_inode->i_mutex); | 2310 | mutex_unlock(&dir->d_inode->i_mutex); |
2314 | 2311 | ||
2315 | done: | 2312 | done: |
2316 | if (!dentry->d_inode || d_is_negative(dentry)) { | 2313 | if (d_is_negative(dentry)) { |
2317 | error = -ENOENT; | 2314 | error = -ENOENT; |
2318 | dput(dentry); | 2315 | dput(dentry); |
2319 | goto out; | 2316 | goto out; |
@@ -2341,7 +2338,8 @@ out: | |||
2341 | * Returns 0 and "path" will be valid on success; Returns error otherwise. | 2338 | * Returns 0 and "path" will be valid on success; Returns error otherwise. |
2342 | */ | 2339 | */ |
2343 | static int | 2340 | static int |
2344 | path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags) | 2341 | path_mountpoint(int dfd, const struct filename *name, struct path *path, |
2342 | unsigned int flags) | ||
2345 | { | 2343 | { |
2346 | struct nameidata nd; | 2344 | struct nameidata nd; |
2347 | int err; | 2345 | int err; |
@@ -2370,20 +2368,20 @@ out: | |||
2370 | } | 2368 | } |
2371 | 2369 | ||
2372 | static int | 2370 | static int |
2373 | filename_mountpoint(int dfd, struct filename *s, struct path *path, | 2371 | filename_mountpoint(int dfd, struct filename *name, struct path *path, |
2374 | unsigned int flags) | 2372 | unsigned int flags) |
2375 | { | 2373 | { |
2376 | int error; | 2374 | int error; |
2377 | if (IS_ERR(s)) | 2375 | if (IS_ERR(name)) |
2378 | return PTR_ERR(s); | 2376 | return PTR_ERR(name); |
2379 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU); | 2377 | error = path_mountpoint(dfd, name, path, flags | LOOKUP_RCU); |
2380 | if (unlikely(error == -ECHILD)) | 2378 | if (unlikely(error == -ECHILD)) |
2381 | error = path_mountpoint(dfd, s->name, path, flags); | 2379 | error = path_mountpoint(dfd, name, path, flags); |
2382 | if (unlikely(error == -ESTALE)) | 2380 | if (unlikely(error == -ESTALE)) |
2383 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL); | 2381 | error = path_mountpoint(dfd, name, path, flags | LOOKUP_REVAL); |
2384 | if (likely(!error)) | 2382 | if (likely(!error)) |
2385 | audit_inode(s, path->dentry, 0); | 2383 | audit_inode(name, path->dentry, 0); |
2386 | putname(s); | 2384 | putname(name); |
2387 | return error; | 2385 | return error; |
2388 | } | 2386 | } |
2389 | 2387 | ||
@@ -3040,7 +3038,7 @@ retry_lookup: | |||
3040 | finish_lookup: | 3038 | finish_lookup: |
3041 | /* we _can_ be in RCU mode here */ | 3039 | /* we _can_ be in RCU mode here */ |
3042 | error = -ENOENT; | 3040 | error = -ENOENT; |
3043 | if (!inode || d_is_negative(path->dentry)) { | 3041 | if (d_is_negative(path->dentry)) { |
3044 | path_to_nameidata(path, nd); | 3042 | path_to_nameidata(path, nd); |
3045 | goto out; | 3043 | goto out; |
3046 | } | 3044 | } |
@@ -3079,7 +3077,7 @@ finish_open: | |||
3079 | error = -ENOTDIR; | 3077 | error = -ENOTDIR; |
3080 | if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) | 3078 | if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) |
3081 | goto out; | 3079 | goto out; |
3082 | if (!S_ISREG(nd->inode->i_mode)) | 3080 | if (!d_is_reg(nd->path.dentry)) |
3083 | will_truncate = false; | 3081 | will_truncate = false; |
3084 | 3082 | ||
3085 | if (will_truncate) { | 3083 | if (will_truncate) { |
@@ -3156,7 +3154,7 @@ static int do_tmpfile(int dfd, struct filename *pathname, | |||
3156 | static const struct qstr name = QSTR_INIT("/", 1); | 3154 | static const struct qstr name = QSTR_INIT("/", 1); |
3157 | struct dentry *dentry, *child; | 3155 | struct dentry *dentry, *child; |
3158 | struct inode *dir; | 3156 | struct inode *dir; |
3159 | int error = path_lookupat(dfd, pathname->name, | 3157 | int error = path_lookupat(dfd, pathname, |
3160 | flags | LOOKUP_DIRECTORY, nd); | 3158 | flags | LOOKUP_DIRECTORY, nd); |
3161 | if (unlikely(error)) | 3159 | if (unlikely(error)) |
3162 | return error; | 3160 | return error; |
@@ -3229,7 +3227,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, | |||
3229 | goto out; | 3227 | goto out; |
3230 | } | 3228 | } |
3231 | 3229 | ||
3232 | error = path_init(dfd, pathname->name, flags, nd); | 3230 | error = path_init(dfd, pathname, flags, nd); |
3233 | if (unlikely(error)) | 3231 | if (unlikely(error)) |
3234 | goto out; | 3232 | goto out; |
3235 | 3233 | ||