Commit b0990fbb authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: check IS_APPEND() on real upper inode

For overlay file open, check IS_APPEND() on the real upper inode
inside d_real(), because the overlay inode does not have the
S_APPEND flag and IS_APPEND() can only be checked at open time.

Note that because overlayfs does not copy up the chattr inode flags
(i.e. S_APPEND, S_IMMUTABLE), the IS_APPEND() check is only relevant
for upper inodes that were set with chattr +a and not to lower
inodes that had chattr +a before copy up.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 78757af6
...@@ -49,11 +49,28 @@ static void ovl_dentry_release(struct dentry *dentry) ...@@ -49,11 +49,28 @@ static void ovl_dentry_release(struct dentry *dentry)
} }
} }
static int ovl_check_append_only(struct inode *inode, int flag)
{
/*
* This test was moot in vfs may_open() because overlay inode does
* not have the S_APPEND flag, so re-check on real upper inode
*/
if (IS_APPEND(inode)) {
if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND))
return -EPERM;
if (flag & O_TRUNC)
return -EPERM;
}
return 0;
}
static struct dentry *ovl_d_real(struct dentry *dentry, static struct dentry *ovl_d_real(struct dentry *dentry,
const struct inode *inode, const struct inode *inode,
unsigned int open_flags) unsigned int open_flags)
{ {
struct dentry *real; struct dentry *real;
int err;
if (!d_is_reg(dentry)) { if (!d_is_reg(dentry)) {
if (!inode || inode == d_inode(dentry)) if (!inode || inode == d_inode(dentry))
...@@ -65,15 +82,20 @@ static struct dentry *ovl_d_real(struct dentry *dentry, ...@@ -65,15 +82,20 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
return dentry; return dentry;
if (open_flags) { if (open_flags) {
int err = ovl_open_maybe_copy_up(dentry, open_flags); err = ovl_open_maybe_copy_up(dentry, open_flags);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
} }
real = ovl_dentry_upper(dentry); real = ovl_dentry_upper(dentry);
if (real && (!inode || inode == d_inode(real))) if (real && (!inode || inode == d_inode(real))) {
if (!inode) {
err = ovl_check_append_only(d_inode(real), open_flags);
if (err)
return ERR_PTR(err);
}
return real; return real;
}
real = ovl_dentry_lower(dentry); real = ovl_dentry_lower(dentry);
if (!real) if (!real)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment