~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/overlayfs/inode.c

Version: ~ [ linux-5.8-rc3 ] ~ [ linux-5.7.5 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.48 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.129 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.185 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.228 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.228 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *
  3  * Copyright (C) 2011 Novell Inc.
  4  *
  5  * This program is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 as published by
  7  * the Free Software Foundation.
  8  */
  9 
 10 #include <linux/fs.h>
 11 #include <linux/slab.h>
 12 #include <linux/xattr.h>
 13 #include "overlayfs.h"
 14 
 15 static int ovl_copy_up_truncate(struct dentry *dentry)
 16 {
 17         int err;
 18         struct dentry *parent;
 19         struct kstat stat;
 20         struct path lowerpath;
 21 
 22         parent = dget_parent(dentry);
 23         err = ovl_copy_up(parent);
 24         if (err)
 25                 goto out_dput_parent;
 26 
 27         ovl_path_lower(dentry, &lowerpath);
 28         err = vfs_getattr(&lowerpath, &stat);
 29         if (err)
 30                 goto out_dput_parent;
 31 
 32         stat.size = 0;
 33         err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
 34 
 35 out_dput_parent:
 36         dput(parent);
 37         return err;
 38 }
 39 
 40 int ovl_setattr(struct dentry *dentry, struct iattr *attr)
 41 {
 42         int err;
 43         struct dentry *upperdentry;
 44 
 45         /*
 46          * Check for permissions before trying to copy-up.  This is redundant
 47          * since it will be rechecked later by ->setattr() on upper dentry.  But
 48          * without this, copy-up can be triggered by just about anybody.
 49          *
 50          * We don't initialize inode->size, which just means that
 51          * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
 52          * check for a swapfile (which this won't be anyway).
 53          */
 54         err = inode_change_ok(dentry->d_inode, attr);
 55         if (err)
 56                 return err;
 57 
 58         err = ovl_want_write(dentry);
 59         if (err)
 60                 goto out;
 61 
 62         if (attr->ia_valid & ATTR_SIZE) {
 63                 struct inode *realinode = d_inode(ovl_dentry_real(dentry));
 64 
 65                 err = -ETXTBSY;
 66                 if (atomic_read(&realinode->i_writecount) < 0)
 67                         goto out_drop_write;
 68         }
 69 
 70         err = ovl_copy_up(dentry);
 71         if (!err) {
 72                 struct inode *winode = NULL;
 73 
 74                 upperdentry = ovl_dentry_upper(dentry);
 75 
 76                 if (attr->ia_valid & ATTR_SIZE) {
 77                         winode = d_inode(upperdentry);
 78                         err = get_write_access(winode);
 79                         if (err)
 80                                 goto out_drop_write;
 81                 }
 82 
 83                 if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
 84                         attr->ia_valid &= ~ATTR_MODE;
 85 
 86                 inode_lock(upperdentry->d_inode);
 87                 err = notify_change(upperdentry, attr, NULL);
 88                 if (!err)
 89                         ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
 90                 inode_unlock(upperdentry->d_inode);
 91 
 92                 if (winode)
 93                         put_write_access(winode);
 94         }
 95 out_drop_write:
 96         ovl_drop_write(dentry);
 97 out:
 98         return err;
 99 }
100 
101 static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
102                          struct kstat *stat)
103 {
104         struct path realpath;
105 
106         ovl_path_real(dentry, &realpath);
107         return vfs_getattr(&realpath, stat);
108 }
109 
110 int ovl_permission(struct inode *inode, int mask)
111 {
112         struct ovl_entry *oe;
113         struct dentry *alias = NULL;
114         struct inode *realinode;
115         struct dentry *realdentry;
116         bool is_upper;
117         int err;
118 
119         if (S_ISDIR(inode->i_mode)) {
120                 oe = inode->i_private;
121         } else if (mask & MAY_NOT_BLOCK) {
122                 return -ECHILD;
123         } else {
124                 /*
125                  * For non-directories find an alias and get the info
126                  * from there.
127                  */
128                 alias = d_find_any_alias(inode);
129                 if (WARN_ON(!alias))
130                         return -ENOENT;
131 
132                 oe = alias->d_fsdata;
133         }
134 
135         realdentry = ovl_entry_real(oe, &is_upper);
136 
137         if (ovl_is_default_permissions(inode)) {
138                 struct kstat stat;
139                 struct path realpath = { .dentry = realdentry };
140 
141                 if (mask & MAY_NOT_BLOCK)
142                         return -ECHILD;
143 
144                 realpath.mnt = ovl_entry_mnt_real(oe, inode, is_upper);
145 
146                 err = vfs_getattr(&realpath, &stat);
147                 if (err)
148                         goto out_dput;
149 
150                 err = -ESTALE;
151                 if ((stat.mode ^ inode->i_mode) & S_IFMT)
152                         goto out_dput;
153 
154                 inode->i_mode = stat.mode;
155                 inode->i_uid = stat.uid;
156                 inode->i_gid = stat.gid;
157 
158                 err = generic_permission(inode, mask);
159                 goto out_dput;
160         }
161 
162         /* Careful in RCU walk mode */
163         realinode = ACCESS_ONCE(realdentry->d_inode);
164         if (!realinode) {
165                 WARN_ON(!(mask & MAY_NOT_BLOCK));
166                 err = -ENOENT;
167                 goto out_dput;
168         }
169 
170         if (mask & MAY_WRITE) {
171                 umode_t mode = realinode->i_mode;
172 
173                 /*
174                  * Writes will always be redirected to upper layer, so
175                  * ignore lower layer being read-only.
176                  *
177                  * If the overlay itself is read-only then proceed
178                  * with the permission check, don't return EROFS.
179                  * This will only happen if this is the lower layer of
180                  * another overlayfs.
181                  *
182                  * If upper fs becomes read-only after the overlay was
183                  * constructed return EROFS to prevent modification of
184                  * upper layer.
185                  */
186                 err = -EROFS;
187                 if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) &&
188                     (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
189                         goto out_dput;
190         }
191 
192         err = __inode_permission(realinode, mask);
193 out_dput:
194         dput(alias);
195         return err;
196 }
197 
198 static const char *ovl_get_link(struct dentry *dentry,
199                                 struct inode *inode,
200                                 struct delayed_call *done)
201 {
202         struct dentry *realdentry;
203         struct inode *realinode;
204 
205         if (!dentry)
206                 return ERR_PTR(-ECHILD);
207 
208         realdentry = ovl_dentry_real(dentry);
209         realinode = realdentry->d_inode;
210 
211         if (WARN_ON(!realinode->i_op->get_link))
212                 return ERR_PTR(-EPERM);
213 
214         return realinode->i_op->get_link(realdentry, realinode, done);
215 }
216 
217 static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
218 {
219         struct path realpath;
220         struct inode *realinode;
221 
222         ovl_path_real(dentry, &realpath);
223         realinode = realpath.dentry->d_inode;
224 
225         if (!realinode->i_op->readlink)
226                 return -EINVAL;
227 
228         touch_atime(&realpath);
229 
230         return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
231 }
232 
233 
234 static bool ovl_is_private_xattr(const char *name)
235 {
236         return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
237 }
238 
239 int ovl_setxattr(struct dentry *dentry, const char *name,
240                  const void *value, size_t size, int flags)
241 {
242         int err;
243         struct dentry *upperdentry;
244 
245         err = ovl_want_write(dentry);
246         if (err)
247                 goto out;
248 
249         err = -EPERM;
250         if (ovl_is_private_xattr(name))
251                 goto out_drop_write;
252 
253         err = ovl_copy_up(dentry);
254         if (err)
255                 goto out_drop_write;
256 
257         upperdentry = ovl_dentry_upper(dentry);
258         err = vfs_setxattr(upperdentry, name, value, size, flags);
259 
260 out_drop_write:
261         ovl_drop_write(dentry);
262 out:
263         return err;
264 }
265 
266 static bool ovl_need_xattr_filter(struct dentry *dentry,
267                                   enum ovl_path_type type)
268 {
269         if ((type & (__OVL_PATH_PURE | __OVL_PATH_UPPER)) == __OVL_PATH_UPPER)
270                 return S_ISDIR(dentry->d_inode->i_mode);
271         else
272                 return false;
273 }
274 
275 ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
276                      void *value, size_t size)
277 {
278         struct path realpath;
279         enum ovl_path_type type = ovl_path_real(dentry, &realpath);
280 
281         if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
282                 return -ENODATA;
283 
284         return vfs_getxattr(realpath.dentry, name, value, size);
285 }
286 
287 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
288 {
289         struct path realpath;
290         enum ovl_path_type type = ovl_path_real(dentry, &realpath);
291         ssize_t res;
292         int off;
293 
294         res = vfs_listxattr(realpath.dentry, list, size);
295         if (res <= 0 || size == 0)
296                 return res;
297 
298         if (!ovl_need_xattr_filter(dentry, type))
299                 return res;
300 
301         /* filter out private xattrs */
302         for (off = 0; off < res;) {
303                 char *s = list + off;
304                 size_t slen = strlen(s) + 1;
305 
306                 BUG_ON(off + slen > res);
307 
308                 if (ovl_is_private_xattr(s)) {
309                         res -= slen;
310                         memmove(s, s + slen, res - off);
311                 } else {
312                         off += slen;
313                 }
314         }
315 
316         return res;
317 }
318 
319 int ovl_removexattr(struct dentry *dentry, const char *name)
320 {
321         int err;
322         struct path realpath;
323         enum ovl_path_type type = ovl_path_real(dentry, &realpath);
324 
325         err = ovl_want_write(dentry);
326         if (err)
327                 goto out;
328 
329         err = -ENODATA;
330         if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
331                 goto out_drop_write;
332 
333         if (!OVL_TYPE_UPPER(type)) {
334                 err = vfs_getxattr(realpath.dentry, name, NULL, 0);
335                 if (err < 0)
336                         goto out_drop_write;
337 
338                 err = ovl_copy_up(dentry);
339                 if (err)
340                         goto out_drop_write;
341 
342                 ovl_path_upper(dentry, &realpath);
343         }
344 
345         err = vfs_removexattr(realpath.dentry, name);
346 out_drop_write:
347         ovl_drop_write(dentry);
348 out:
349         return err;
350 }
351 
352 static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
353                                   struct dentry *realdentry)
354 {
355         if (OVL_TYPE_UPPER(type))
356                 return false;
357 
358         if (special_file(realdentry->d_inode->i_mode))
359                 return false;
360 
361         if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
362                 return false;
363 
364         return true;
365 }
366 
367 struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
368 {
369         int err;
370         struct path realpath;
371         enum ovl_path_type type;
372 
373         if (d_is_dir(dentry))
374                 return d_backing_inode(dentry);
375 
376         type = ovl_path_real(dentry, &realpath);
377         if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
378                 err = ovl_want_write(dentry);
379                 if (err)
380                         return ERR_PTR(err);
381 
382                 if (file_flags & O_TRUNC)
383                         err = ovl_copy_up_truncate(dentry);
384                 else
385                         err = ovl_copy_up(dentry);
386                 ovl_drop_write(dentry);
387                 if (err)
388                         return ERR_PTR(err);
389 
390                 ovl_path_upper(dentry, &realpath);
391         }
392 
393         if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE)
394                 return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags);
395 
396         return d_backing_inode(realpath.dentry);
397 }
398 
399 static const struct inode_operations ovl_file_inode_operations = {
400         .setattr        = ovl_setattr,
401         .permission     = ovl_permission,
402         .getattr        = ovl_getattr,
403         .setxattr       = ovl_setxattr,
404         .getxattr       = ovl_getxattr,
405         .listxattr      = ovl_listxattr,
406         .removexattr    = ovl_removexattr,
407 };
408 
409 static const struct inode_operations ovl_symlink_inode_operations = {
410         .setattr        = ovl_setattr,
411         .get_link       = ovl_get_link,
412         .readlink       = ovl_readlink,
413         .getattr        = ovl_getattr,
414         .setxattr       = ovl_setxattr,
415         .getxattr       = ovl_getxattr,
416         .listxattr      = ovl_listxattr,
417         .removexattr    = ovl_removexattr,
418 };
419 
420 struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
421                             struct ovl_entry *oe)
422 {
423         struct inode *inode;
424 
425         inode = new_inode(sb);
426         if (!inode)
427                 return NULL;
428 
429         inode->i_ino = get_next_ino();
430         inode->i_mode = mode;
431         inode->i_flags |= S_NOATIME | S_NOCMTIME;
432 
433         mode &= S_IFMT;
434         switch (mode) {
435         case S_IFDIR:
436                 inode->i_private = oe;
437                 inode->i_op = &ovl_dir_inode_operations;
438                 inode->i_fop = &ovl_dir_operations;
439                 break;
440 
441         case S_IFLNK:
442                 inode->i_op = &ovl_symlink_inode_operations;
443                 break;
444 
445         case S_IFREG:
446         case S_IFSOCK:
447         case S_IFBLK:
448         case S_IFCHR:
449         case S_IFIFO:
450                 inode->i_op = &ovl_file_inode_operations;
451                 break;
452 
453         default:
454                 WARN(1, "illegal file type: %i\n", mode);
455                 iput(inode);
456                 inode = NULL;
457         }
458 
459         return inode;
460 }
461 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp