diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2016-10-04 08:40:45 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-10-14 05:16:47 -0400 |
commit | 7764235becf3b72bd124400fbffe670531322135 (patch) | |
tree | 9377570db6422ab76c10617bea548a1f4e41311e | |
parent | d60874cd58fcb21372f2df698c20f8cf2f78fdcb (diff) |
ovl: use vfs_get_link()
Resulting in a complete removal of a function basically implementing the
inverse of vfs_readlink().
As a bonus, now the proper security hook is also called.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | fs/overlayfs/copy_up.c | 46 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 10 |
2 files changed, 7 insertions, 49 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 796d06fafd09..e9d4013ed3c6 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -177,40 +177,6 @@ out_fput: | |||
177 | return error; | 177 | return error; |
178 | } | 178 | } |
179 | 179 | ||
180 | static char *ovl_read_symlink(struct dentry *realdentry) | ||
181 | { | ||
182 | int res; | ||
183 | char *buf; | ||
184 | struct inode *inode = realdentry->d_inode; | ||
185 | mm_segment_t old_fs; | ||
186 | |||
187 | res = -EINVAL; | ||
188 | if (!inode->i_op->readlink) | ||
189 | goto err; | ||
190 | |||
191 | res = -ENOMEM; | ||
192 | buf = (char *) __get_free_page(GFP_KERNEL); | ||
193 | if (!buf) | ||
194 | goto err; | ||
195 | |||
196 | old_fs = get_fs(); | ||
197 | set_fs(get_ds()); | ||
198 | /* The cast to a user pointer is valid due to the set_fs() */ | ||
199 | res = inode->i_op->readlink(realdentry, | ||
200 | (char __user *)buf, PAGE_SIZE - 1); | ||
201 | set_fs(old_fs); | ||
202 | if (res < 0) { | ||
203 | free_page((unsigned long) buf); | ||
204 | goto err; | ||
205 | } | ||
206 | buf[res] = '\0'; | ||
207 | |||
208 | return buf; | ||
209 | |||
210 | err: | ||
211 | return ERR_PTR(res); | ||
212 | } | ||
213 | |||
214 | static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) | 180 | static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) |
215 | { | 181 | { |
216 | struct iattr attr = { | 182 | struct iattr attr = { |
@@ -342,18 +308,20 @@ out_cleanup: | |||
342 | int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | 308 | int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, |
343 | struct path *lowerpath, struct kstat *stat) | 309 | struct path *lowerpath, struct kstat *stat) |
344 | { | 310 | { |
311 | DEFINE_DELAYED_CALL(done); | ||
345 | struct dentry *workdir = ovl_workdir(dentry); | 312 | struct dentry *workdir = ovl_workdir(dentry); |
346 | int err; | 313 | int err; |
347 | struct kstat pstat; | 314 | struct kstat pstat; |
348 | struct path parentpath; | 315 | struct path parentpath; |
316 | struct dentry *lowerdentry = lowerpath->dentry; | ||
349 | struct dentry *upperdir; | 317 | struct dentry *upperdir; |
350 | struct dentry *upperdentry; | 318 | struct dentry *upperdentry; |
351 | char *link = NULL; | 319 | const char *link = NULL; |
352 | 320 | ||
353 | if (WARN_ON(!workdir)) | 321 | if (WARN_ON(!workdir)) |
354 | return -EROFS; | 322 | return -EROFS; |
355 | 323 | ||
356 | ovl_do_check_copy_up(lowerpath->dentry); | 324 | ovl_do_check_copy_up(lowerdentry); |
357 | 325 | ||
358 | ovl_path_upper(parent, &parentpath); | 326 | ovl_path_upper(parent, &parentpath); |
359 | upperdir = parentpath.dentry; | 327 | upperdir = parentpath.dentry; |
@@ -363,7 +331,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
363 | return err; | 331 | return err; |
364 | 332 | ||
365 | if (S_ISLNK(stat->mode)) { | 333 | if (S_ISLNK(stat->mode)) { |
366 | link = ovl_read_symlink(lowerpath->dentry); | 334 | link = vfs_get_link(lowerdentry, &done); |
367 | if (IS_ERR(link)) | 335 | if (IS_ERR(link)) |
368 | return PTR_ERR(link); | 336 | return PTR_ERR(link); |
369 | } | 337 | } |
@@ -388,9 +356,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
388 | } | 356 | } |
389 | out_unlock: | 357 | out_unlock: |
390 | unlock_rename(workdir, upperdir); | 358 | unlock_rename(workdir, upperdir); |
391 | 359 | do_delayed_call(&done); | |
392 | if (link) | ||
393 | free_page((unsigned long) link); | ||
394 | 360 | ||
395 | return err; | 361 | return err; |
396 | } | 362 | } |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 50dc214c44f2..bc6d261db669 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
@@ -156,22 +156,14 @@ static const char *ovl_get_link(struct dentry *dentry, | |||
156 | struct inode *inode, | 156 | struct inode *inode, |
157 | struct delayed_call *done) | 157 | struct delayed_call *done) |
158 | { | 158 | { |
159 | struct dentry *realdentry; | ||
160 | struct inode *realinode; | ||
161 | const struct cred *old_cred; | 159 | const struct cred *old_cred; |
162 | const char *p; | 160 | const char *p; |
163 | 161 | ||
164 | if (!dentry) | 162 | if (!dentry) |
165 | return ERR_PTR(-ECHILD); | 163 | return ERR_PTR(-ECHILD); |
166 | 164 | ||
167 | realdentry = ovl_dentry_real(dentry); | ||
168 | realinode = realdentry->d_inode; | ||
169 | |||
170 | if (WARN_ON(!realinode->i_op->get_link)) | ||
171 | return ERR_PTR(-EPERM); | ||
172 | |||
173 | old_cred = ovl_override_creds(dentry->d_sb); | 165 | old_cred = ovl_override_creds(dentry->d_sb); |
174 | p = realinode->i_op->get_link(realdentry, realinode, done); | 166 | p = vfs_get_link(ovl_dentry_real(dentry), done); |
175 | revert_creds(old_cred); | 167 | revert_creds(old_cred); |
176 | return p; | 168 | return p; |
177 | } | 169 | } |