diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-03-14 13:42:45 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-01 23:19:15 -0400 |
commit | 5d826c847b34de6415b4f1becd88a57ff619af50 (patch) | |
tree | 431338c4141bcff1d392f232613841bf1971d99b | |
parent | 4efcc9ffcd4fc53f1f7de539842cdffa1f8e5ecc (diff) |
new helper: readlink_copy()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 13 | ||||
-rw-r--r-- | fs/proc/namespaces.c | 14 | ||||
-rw-r--r-- | fs/proc/self.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 28 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
5 files changed, 12 insertions, 47 deletions
diff --git a/fs/namei.c b/fs/namei.c index 617de9e9967b..4fb52f0ca5cb 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -4297,11 +4297,9 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna | |||
4297 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | 4297 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); |
4298 | } | 4298 | } |
4299 | 4299 | ||
4300 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 4300 | int readlink_copy(char __user *buffer, int buflen, const char *link) |
4301 | { | 4301 | { |
4302 | int len; | 4302 | int len = PTR_ERR(link); |
4303 | |||
4304 | len = PTR_ERR(link); | ||
4305 | if (IS_ERR(link)) | 4303 | if (IS_ERR(link)) |
4306 | goto out; | 4304 | goto out; |
4307 | 4305 | ||
@@ -4313,7 +4311,7 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const c | |||
4313 | out: | 4311 | out: |
4314 | return len; | 4312 | return len; |
4315 | } | 4313 | } |
4316 | EXPORT_SYMBOL(vfs_readlink); | 4314 | EXPORT_SYMBOL(readlink_copy); |
4317 | 4315 | ||
4318 | /* | 4316 | /* |
4319 | * A helper for ->readlink(). This should be used *ONLY* for symlinks that | 4317 | * A helper for ->readlink(). This should be used *ONLY* for symlinks that |
@@ -4331,7 +4329,7 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |||
4331 | if (IS_ERR(cookie)) | 4329 | if (IS_ERR(cookie)) |
4332 | return PTR_ERR(cookie); | 4330 | return PTR_ERR(cookie); |
4333 | 4331 | ||
4334 | res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); | 4332 | res = readlink_copy(buffer, buflen, nd_get_link(&nd)); |
4335 | if (dentry->d_inode->i_op->put_link) | 4333 | if (dentry->d_inode->i_op->put_link) |
4336 | dentry->d_inode->i_op->put_link(dentry, &nd, cookie); | 4334 | dentry->d_inode->i_op->put_link(dentry, &nd, cookie); |
4337 | return res; | 4335 | return res; |
@@ -4356,8 +4354,7 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage) | |||
4356 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) | 4354 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) |
4357 | { | 4355 | { |
4358 | struct page *page = NULL; | 4356 | struct page *page = NULL; |
4359 | char *s = page_getlink(dentry, &page); | 4357 | int res = readlink_copy(buffer, buflen, page_getlink(dentry, &page)); |
4360 | int res = vfs_readlink(dentry,buffer,buflen,s); | ||
4361 | if (page) { | 4358 | if (page) { |
4362 | kunmap(page); | 4359 | kunmap(page); |
4363 | page_cache_release(page); | 4360 | page_cache_release(page); |
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 9ae46b87470d..89026095f2b5 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
@@ -146,7 +146,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl | |||
146 | struct task_struct *task; | 146 | struct task_struct *task; |
147 | void *ns; | 147 | void *ns; |
148 | char name[50]; | 148 | char name[50]; |
149 | int len = -EACCES; | 149 | int res = -EACCES; |
150 | 150 | ||
151 | task = get_proc_task(inode); | 151 | task = get_proc_task(inode); |
152 | if (!task) | 152 | if (!task) |
@@ -155,24 +155,18 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl | |||
155 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 155 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
156 | goto out_put_task; | 156 | goto out_put_task; |
157 | 157 | ||
158 | len = -ENOENT; | 158 | res = -ENOENT; |
159 | ns = ns_ops->get(task); | 159 | ns = ns_ops->get(task); |
160 | if (!ns) | 160 | if (!ns) |
161 | goto out_put_task; | 161 | goto out_put_task; |
162 | 162 | ||
163 | snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); | 163 | snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); |
164 | len = strlen(name); | 164 | res = readlink_copy(buffer, buflen, name); |
165 | |||
166 | if (len > buflen) | ||
167 | len = buflen; | ||
168 | if (copy_to_user(buffer, name, len)) | ||
169 | len = -EFAULT; | ||
170 | |||
171 | ns_ops->put(ns); | 165 | ns_ops->put(ns); |
172 | out_put_task: | 166 | out_put_task: |
173 | put_task_struct(task); | 167 | put_task_struct(task); |
174 | out: | 168 | out: |
175 | return len; | 169 | return res; |
176 | } | 170 | } |
177 | 171 | ||
178 | static const struct inode_operations proc_ns_link_inode_operations = { | 172 | static const struct inode_operations proc_ns_link_inode_operations = { |
diff --git a/fs/proc/self.c b/fs/proc/self.c index ffeb202ec942..4348bb8907c2 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c | |||
@@ -16,7 +16,7 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | |||
16 | if (!tgid) | 16 | if (!tgid) |
17 | return -ENOENT; | 17 | return -ENOENT; |
18 | sprintf(tmp, "%d", tgid); | 18 | sprintf(tmp, "%d", tgid); |
19 | return vfs_readlink(dentry,buffer,buflen,tmp); | 19 | return readlink_copy(buffer, buflen, tmp); |
20 | } | 20 | } |
21 | 21 | ||
22 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | 22 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index bcfe61202115..0b18776b075e 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -271,32 +271,6 @@ xfs_open_by_handle( | |||
271 | return error; | 271 | return error; |
272 | } | 272 | } |
273 | 273 | ||
274 | /* | ||
275 | * This is a copy from fs/namei.c:vfs_readlink(), except for removing it's | ||
276 | * unused first argument. | ||
277 | */ | ||
278 | STATIC int | ||
279 | do_readlink( | ||
280 | char __user *buffer, | ||
281 | int buflen, | ||
282 | const char *link) | ||
283 | { | ||
284 | int len; | ||
285 | |||
286 | len = PTR_ERR(link); | ||
287 | if (IS_ERR(link)) | ||
288 | goto out; | ||
289 | |||
290 | len = strlen(link); | ||
291 | if (len > (unsigned) buflen) | ||
292 | len = buflen; | ||
293 | if (copy_to_user(buffer, link, len)) | ||
294 | len = -EFAULT; | ||
295 | out: | ||
296 | return len; | ||
297 | } | ||
298 | |||
299 | |||
300 | int | 274 | int |
301 | xfs_readlink_by_handle( | 275 | xfs_readlink_by_handle( |
302 | struct file *parfilp, | 276 | struct file *parfilp, |
@@ -334,7 +308,7 @@ xfs_readlink_by_handle( | |||
334 | error = -xfs_readlink(XFS_I(dentry->d_inode), link); | 308 | error = -xfs_readlink(XFS_I(dentry->d_inode), link); |
335 | if (error) | 309 | if (error) |
336 | goto out_kfree; | 310 | goto out_kfree; |
337 | error = do_readlink(hreq->ohandle, olen, link); | 311 | error = readlink_copy(hreq->ohandle, olen, link); |
338 | if (error) | 312 | if (error) |
339 | goto out_kfree; | 313 | goto out_kfree; |
340 | 314 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index d9d88a0b456e..db181b542db1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2517,7 +2517,7 @@ extern const struct file_operations generic_ro_fops; | |||
2517 | 2517 | ||
2518 | #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) | 2518 | #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) |
2519 | 2519 | ||
2520 | extern int vfs_readlink(struct dentry *, char __user *, int, const char *); | 2520 | extern int readlink_copy(char __user *, int, const char *); |
2521 | extern int page_readlink(struct dentry *, char __user *, int); | 2521 | extern int page_readlink(struct dentry *, char __user *, int); |
2522 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); | 2522 | extern void *page_follow_link_light(struct dentry *, struct nameidata *); |
2523 | extern void page_put_link(struct dentry *, struct nameidata *, void *); | 2523 | extern void page_put_link(struct dentry *, struct nameidata *, void *); |