diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/exec.c | 10 | ||||
-rw-r--r-- | fs/namei.c | 143 | ||||
-rw-r--r-- | fs/open.c | 10 |
3 files changed, 106 insertions, 57 deletions
@@ -794,8 +794,14 @@ exit: | |||
794 | 794 | ||
795 | struct file *open_exec(const char *name) | 795 | struct file *open_exec(const char *name) |
796 | { | 796 | { |
797 | struct filename tmp = { .name = name }; | 797 | struct filename *filename = getname_kernel(name); |
798 | return do_open_execat(AT_FDCWD, &tmp, 0); | 798 | struct file *f = ERR_CAST(filename); |
799 | |||
800 | if (!IS_ERR(filename)) { | ||
801 | f = do_open_execat(AT_FDCWD, filename, 0); | ||
802 | putname(filename); | ||
803 | } | ||
804 | return f; | ||
799 | } | 805 | } |
800 | EXPORT_SYMBOL(open_exec); | 806 | EXPORT_SYMBOL(open_exec); |
801 | 807 | ||
diff --git a/fs/namei.c b/fs/namei.c index bc35b02883bb..96ca11dea4a2 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -118,15 +118,6 @@ | |||
118 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). | 118 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). |
119 | * PATH_MAX includes the nul terminator --RR. | 119 | * PATH_MAX includes the nul terminator --RR. |
120 | */ | 120 | */ |
121 | void final_putname(struct filename *name) | ||
122 | { | ||
123 | if (name->separate) { | ||
124 | __putname(name->name); | ||
125 | kfree(name); | ||
126 | } else { | ||
127 | __putname(name); | ||
128 | } | ||
129 | } | ||
130 | 121 | ||
131 | #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) | 122 | #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) |
132 | 123 | ||
@@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty) | |||
145 | result = __getname(); | 136 | result = __getname(); |
146 | if (unlikely(!result)) | 137 | if (unlikely(!result)) |
147 | return ERR_PTR(-ENOMEM); | 138 | return ERR_PTR(-ENOMEM); |
139 | result->refcnt = 1; | ||
148 | 140 | ||
149 | /* | 141 | /* |
150 | * First, try to embed the struct filename inside the names_cache | 142 | * First, try to embed the struct filename inside the names_cache |
@@ -179,6 +171,7 @@ recopy: | |||
179 | } | 171 | } |
180 | result->name = kname; | 172 | result->name = kname; |
181 | result->separate = true; | 173 | result->separate = true; |
174 | result->refcnt = 1; | ||
182 | max = PATH_MAX; | 175 | max = PATH_MAX; |
183 | goto recopy; | 176 | goto recopy; |
184 | } | 177 | } |
@@ -202,7 +195,7 @@ recopy: | |||
202 | return result; | 195 | return result; |
203 | 196 | ||
204 | error: | 197 | error: |
205 | final_putname(result); | 198 | putname(result); |
206 | return err; | 199 | return err; |
207 | } | 200 | } |
208 | 201 | ||
@@ -212,43 +205,56 @@ getname(const char __user * filename) | |||
212 | return getname_flags(filename, 0, NULL); | 205 | return getname_flags(filename, 0, NULL); |
213 | } | 206 | } |
214 | 207 | ||
215 | /* | ||
216 | * The "getname_kernel()" interface doesn't do pathnames longer | ||
217 | * than EMBEDDED_NAME_MAX. Deal with it - you're a kernel user. | ||
218 | */ | ||
219 | struct filename * | 208 | struct filename * |
220 | getname_kernel(const char * filename) | 209 | getname_kernel(const char * filename) |
221 | { | 210 | { |
222 | struct filename *result; | 211 | struct filename *result; |
223 | char *kname; | 212 | int len = strlen(filename) + 1; |
224 | int len; | ||
225 | |||
226 | len = strlen(filename); | ||
227 | if (len >= EMBEDDED_NAME_MAX) | ||
228 | return ERR_PTR(-ENAMETOOLONG); | ||
229 | 213 | ||
230 | result = __getname(); | 214 | result = __getname(); |
231 | if (unlikely(!result)) | 215 | if (unlikely(!result)) |
232 | return ERR_PTR(-ENOMEM); | 216 | return ERR_PTR(-ENOMEM); |
233 | 217 | ||
234 | kname = (char *)result + sizeof(*result); | 218 | if (len <= EMBEDDED_NAME_MAX) { |
235 | result->name = kname; | 219 | result->name = (char *)(result) + sizeof(*result); |
220 | result->separate = false; | ||
221 | } else if (len <= PATH_MAX) { | ||
222 | struct filename *tmp; | ||
223 | |||
224 | tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); | ||
225 | if (unlikely(!tmp)) { | ||
226 | __putname(result); | ||
227 | return ERR_PTR(-ENOMEM); | ||
228 | } | ||
229 | tmp->name = (char *)result; | ||
230 | tmp->separate = true; | ||
231 | result = tmp; | ||
232 | } else { | ||
233 | __putname(result); | ||
234 | return ERR_PTR(-ENAMETOOLONG); | ||
235 | } | ||
236 | memcpy((char *)result->name, filename, len); | ||
236 | result->uptr = NULL; | 237 | result->uptr = NULL; |
237 | result->aname = NULL; | 238 | result->aname = NULL; |
238 | result->separate = false; | 239 | result->refcnt = 1; |
240 | audit_getname(result); | ||
239 | 241 | ||
240 | strlcpy(kname, filename, EMBEDDED_NAME_MAX); | ||
241 | return result; | 242 | return result; |
242 | } | 243 | } |
243 | 244 | ||
244 | #ifdef CONFIG_AUDITSYSCALL | ||
245 | void putname(struct filename *name) | 245 | void putname(struct filename *name) |
246 | { | 246 | { |
247 | if (unlikely(!audit_dummy_context())) | 247 | BUG_ON(name->refcnt <= 0); |
248 | return audit_putname(name); | 248 | |
249 | final_putname(name); | 249 | if (--name->refcnt > 0) |
250 | return; | ||
251 | |||
252 | if (name->separate) { | ||
253 | __putname(name->name); | ||
254 | kfree(name); | ||
255 | } else | ||
256 | __putname(name); | ||
250 | } | 257 | } |
251 | #endif | ||
252 | 258 | ||
253 | static int check_acl(struct inode *inode, int mask) | 259 | static int check_acl(struct inode *inode, int mask) |
254 | { | 260 | { |
@@ -2036,31 +2042,47 @@ static int filename_lookup(int dfd, struct filename *name, | |||
2036 | static int do_path_lookup(int dfd, const char *name, | 2042 | static int do_path_lookup(int dfd, const char *name, |
2037 | unsigned int flags, struct nameidata *nd) | 2043 | unsigned int flags, struct nameidata *nd) |
2038 | { | 2044 | { |
2039 | struct filename filename = { .name = name }; | 2045 | struct filename *filename = getname_kernel(name); |
2046 | int retval = PTR_ERR(filename); | ||
2040 | 2047 | ||
2041 | return filename_lookup(dfd, &filename, flags, nd); | 2048 | if (!IS_ERR(filename)) { |
2049 | retval = filename_lookup(dfd, filename, flags, nd); | ||
2050 | putname(filename); | ||
2051 | } | ||
2052 | return retval; | ||
2042 | } | 2053 | } |
2043 | 2054 | ||
2044 | /* does lookup, returns the object with parent locked */ | 2055 | /* does lookup, returns the object with parent locked */ |
2045 | struct dentry *kern_path_locked(const char *name, struct path *path) | 2056 | struct dentry *kern_path_locked(const char *name, struct path *path) |
2046 | { | 2057 | { |
2058 | struct filename *filename = getname_kernel(name); | ||
2047 | struct nameidata nd; | 2059 | struct nameidata nd; |
2048 | struct dentry *d; | 2060 | struct dentry *d; |
2049 | int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd); | 2061 | int err; |
2050 | if (err) | 2062 | |
2051 | return ERR_PTR(err); | 2063 | if (IS_ERR(filename)) |
2064 | return ERR_CAST(filename); | ||
2065 | |||
2066 | err = filename_lookup(AT_FDCWD, filename, LOOKUP_PARENT, &nd); | ||
2067 | if (err) { | ||
2068 | d = ERR_PTR(err); | ||
2069 | goto out; | ||
2070 | } | ||
2052 | if (nd.last_type != LAST_NORM) { | 2071 | if (nd.last_type != LAST_NORM) { |
2053 | path_put(&nd.path); | 2072 | path_put(&nd.path); |
2054 | return ERR_PTR(-EINVAL); | 2073 | d = ERR_PTR(-EINVAL); |
2074 | goto out; | ||
2055 | } | 2075 | } |
2056 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 2076 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
2057 | d = __lookup_hash(&nd.last, nd.path.dentry, 0); | 2077 | d = __lookup_hash(&nd.last, nd.path.dentry, 0); |
2058 | if (IS_ERR(d)) { | 2078 | if (IS_ERR(d)) { |
2059 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2079 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
2060 | path_put(&nd.path); | 2080 | path_put(&nd.path); |
2061 | return d; | 2081 | goto out; |
2062 | } | 2082 | } |
2063 | *path = nd.path; | 2083 | *path = nd.path; |
2084 | out: | ||
2085 | putname(filename); | ||
2064 | return d; | 2086 | return d; |
2065 | } | 2087 | } |
2066 | 2088 | ||
@@ -2351,13 +2373,17 @@ static int | |||
2351 | filename_mountpoint(int dfd, struct filename *s, struct path *path, | 2373 | filename_mountpoint(int dfd, struct filename *s, struct path *path, |
2352 | unsigned int flags) | 2374 | unsigned int flags) |
2353 | { | 2375 | { |
2354 | int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU); | 2376 | int error; |
2377 | if (IS_ERR(s)) | ||
2378 | return PTR_ERR(s); | ||
2379 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU); | ||
2355 | if (unlikely(error == -ECHILD)) | 2380 | if (unlikely(error == -ECHILD)) |
2356 | error = path_mountpoint(dfd, s->name, path, flags); | 2381 | error = path_mountpoint(dfd, s->name, path, flags); |
2357 | if (unlikely(error == -ESTALE)) | 2382 | if (unlikely(error == -ESTALE)) |
2358 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL); | 2383 | error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL); |
2359 | if (likely(!error)) | 2384 | if (likely(!error)) |
2360 | audit_inode(s, path->dentry, 0); | 2385 | audit_inode(s, path->dentry, 0); |
2386 | putname(s); | ||
2361 | return error; | 2387 | return error; |
2362 | } | 2388 | } |
2363 | 2389 | ||
@@ -2379,21 +2405,14 @@ int | |||
2379 | user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags, | 2405 | user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags, |
2380 | struct path *path) | 2406 | struct path *path) |
2381 | { | 2407 | { |
2382 | struct filename *s = getname(name); | 2408 | return filename_mountpoint(dfd, getname(name), path, flags); |
2383 | int error; | ||
2384 | if (IS_ERR(s)) | ||
2385 | return PTR_ERR(s); | ||
2386 | error = filename_mountpoint(dfd, s, path, flags); | ||
2387 | putname(s); | ||
2388 | return error; | ||
2389 | } | 2409 | } |
2390 | 2410 | ||
2391 | int | 2411 | int |
2392 | kern_path_mountpoint(int dfd, const char *name, struct path *path, | 2412 | kern_path_mountpoint(int dfd, const char *name, struct path *path, |
2393 | unsigned int flags) | 2413 | unsigned int flags) |
2394 | { | 2414 | { |
2395 | struct filename s = {.name = name}; | 2415 | return filename_mountpoint(dfd, getname_kernel(name), path, flags); |
2396 | return filename_mountpoint(dfd, &s, path, flags); | ||
2397 | } | 2416 | } |
2398 | EXPORT_SYMBOL(kern_path_mountpoint); | 2417 | EXPORT_SYMBOL(kern_path_mountpoint); |
2399 | 2418 | ||
@@ -3273,7 +3292,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
3273 | { | 3292 | { |
3274 | struct nameidata nd; | 3293 | struct nameidata nd; |
3275 | struct file *file; | 3294 | struct file *file; |
3276 | struct filename filename = { .name = name }; | 3295 | struct filename *filename; |
3277 | int flags = op->lookup_flags | LOOKUP_ROOT; | 3296 | int flags = op->lookup_flags | LOOKUP_ROOT; |
3278 | 3297 | ||
3279 | nd.root.mnt = mnt; | 3298 | nd.root.mnt = mnt; |
@@ -3282,15 +3301,20 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
3282 | if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) | 3301 | if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) |
3283 | return ERR_PTR(-ELOOP); | 3302 | return ERR_PTR(-ELOOP); |
3284 | 3303 | ||
3285 | file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU); | 3304 | filename = getname_kernel(name); |
3305 | if (unlikely(IS_ERR(filename))) | ||
3306 | return ERR_CAST(filename); | ||
3307 | |||
3308 | file = path_openat(-1, filename, &nd, op, flags | LOOKUP_RCU); | ||
3286 | if (unlikely(file == ERR_PTR(-ECHILD))) | 3309 | if (unlikely(file == ERR_PTR(-ECHILD))) |
3287 | file = path_openat(-1, &filename, &nd, op, flags); | 3310 | file = path_openat(-1, filename, &nd, op, flags); |
3288 | if (unlikely(file == ERR_PTR(-ESTALE))) | 3311 | if (unlikely(file == ERR_PTR(-ESTALE))) |
3289 | file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL); | 3312 | file = path_openat(-1, filename, &nd, op, flags | LOOKUP_REVAL); |
3313 | putname(filename); | ||
3290 | return file; | 3314 | return file; |
3291 | } | 3315 | } |
3292 | 3316 | ||
3293 | struct dentry *kern_path_create(int dfd, const char *pathname, | 3317 | static struct dentry *filename_create(int dfd, struct filename *name, |
3294 | struct path *path, unsigned int lookup_flags) | 3318 | struct path *path, unsigned int lookup_flags) |
3295 | { | 3319 | { |
3296 | struct dentry *dentry = ERR_PTR(-EEXIST); | 3320 | struct dentry *dentry = ERR_PTR(-EEXIST); |
@@ -3305,7 +3329,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname, | |||
3305 | */ | 3329 | */ |
3306 | lookup_flags &= LOOKUP_REVAL; | 3330 | lookup_flags &= LOOKUP_REVAL; |
3307 | 3331 | ||
3308 | error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd); | 3332 | error = filename_lookup(dfd, name, LOOKUP_PARENT|lookup_flags, &nd); |
3309 | if (error) | 3333 | if (error) |
3310 | return ERR_PTR(error); | 3334 | return ERR_PTR(error); |
3311 | 3335 | ||
@@ -3359,6 +3383,19 @@ out: | |||
3359 | path_put(&nd.path); | 3383 | path_put(&nd.path); |
3360 | return dentry; | 3384 | return dentry; |
3361 | } | 3385 | } |
3386 | |||
3387 | struct dentry *kern_path_create(int dfd, const char *pathname, | ||
3388 | struct path *path, unsigned int lookup_flags) | ||
3389 | { | ||
3390 | struct filename *filename = getname_kernel(pathname); | ||
3391 | struct dentry *res; | ||
3392 | |||
3393 | if (IS_ERR(filename)) | ||
3394 | return ERR_CAST(filename); | ||
3395 | res = filename_create(dfd, filename, path, lookup_flags); | ||
3396 | putname(filename); | ||
3397 | return res; | ||
3398 | } | ||
3362 | EXPORT_SYMBOL(kern_path_create); | 3399 | EXPORT_SYMBOL(kern_path_create); |
3363 | 3400 | ||
3364 | void done_path_create(struct path *path, struct dentry *dentry) | 3401 | void done_path_create(struct path *path, struct dentry *dentry) |
@@ -3377,7 +3414,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, | |||
3377 | struct dentry *res; | 3414 | struct dentry *res; |
3378 | if (IS_ERR(tmp)) | 3415 | if (IS_ERR(tmp)) |
3379 | return ERR_CAST(tmp); | 3416 | return ERR_CAST(tmp); |
3380 | res = kern_path_create(dfd, tmp->name, path, lookup_flags); | 3417 | res = filename_create(dfd, tmp, path, lookup_flags); |
3381 | putname(tmp); | 3418 | putname(tmp); |
3382 | return res; | 3419 | return res; |
3383 | } | 3420 | } |
@@ -968,8 +968,14 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode) | |||
968 | */ | 968 | */ |
969 | struct file *filp_open(const char *filename, int flags, umode_t mode) | 969 | struct file *filp_open(const char *filename, int flags, umode_t mode) |
970 | { | 970 | { |
971 | struct filename name = {.name = filename}; | 971 | struct filename *name = getname_kernel(filename); |
972 | return file_open_name(&name, flags, mode); | 972 | struct file *file = ERR_CAST(name); |
973 | |||
974 | if (!IS_ERR(name)) { | ||
975 | file = file_open_name(name, flags, mode); | ||
976 | putname(name); | ||
977 | } | ||
978 | return file; | ||
973 | } | 979 | } |
974 | EXPORT_SYMBOL(filp_open); | 980 | EXPORT_SYMBOL(filp_open); |
975 | 981 | ||