Commit 38b25697 authored by Miklos Szeredi's avatar Miklos Szeredi

ovl: handle umask and posix_acl_default correctly on creation

Setting MS_POSIXACL in sb->s_flags has the side effect of passing mode to
create functions without masking against umask.

Another problem when creating over a whiteout is that the default posix acl
is not inherited from the parent dir (because the real parent dir at the
time of creation is the work directory).

Fix these problems by:

 a) If upper fs does not have MS_POSIXACL, then mask mode with umask.

 b) If creating over a whiteout, call posix_acl_create() to get the
 inherited acls.  After creation (but before moving to the final
 destination) set these acls on the created file.  posix_acl_create() also
 updates the file creation mode as appropriate.

Fixes: 39a25b2b ("ovl: define ->get_acl() for overlay inodes")
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 0956254a
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include "overlayfs.h" #include "overlayfs.h"
void ovl_cleanup(struct inode *wdir, struct dentry *wdentry) void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
...@@ -186,6 +188,9 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, ...@@ -186,6 +188,9 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
struct dentry *newdentry; struct dentry *newdentry;
int err; int err;
if (!hardlink && !IS_POSIXACL(udir))
stat->mode &= ~current_umask();
inode_lock_nested(udir, I_MUTEX_PARENT); inode_lock_nested(udir, I_MUTEX_PARENT);
newdentry = lookup_one_len(dentry->d_name.name, upperdir, newdentry = lookup_one_len(dentry->d_name.name, upperdir,
dentry->d_name.len); dentry->d_name.len);
...@@ -335,6 +340,32 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry) ...@@ -335,6 +340,32 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
return ret; return ret;
} }
static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
const struct posix_acl *acl)
{
void *buffer;
size_t size;
int err;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl)
return 0;
size = posix_acl_to_xattr(NULL, acl, NULL, 0);
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
size = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
err = size;
if (err < 0)
goto out_free;
err = vfs_setxattr(upperdentry, name, buffer, size, XATTR_CREATE);
out_free:
kfree(buffer);
return err;
}
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
struct kstat *stat, const char *link, struct kstat *stat, const char *link,
struct dentry *hardlink) struct dentry *hardlink)
...@@ -346,10 +377,18 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -346,10 +377,18 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
struct dentry *upper; struct dentry *upper;
struct dentry *newdentry; struct dentry *newdentry;
int err; int err;
struct posix_acl *acl, *default_acl;
if (WARN_ON(!workdir)) if (WARN_ON(!workdir))
return -EROFS; return -EROFS;
if (!hardlink) {
err = posix_acl_create(dentry->d_parent->d_inode,
&stat->mode, &default_acl, &acl);
if (err)
return err;
}
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
if (err) if (err)
goto out; goto out;
...@@ -384,6 +423,17 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -384,6 +423,17 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (err) if (err)
goto out_cleanup; goto out_cleanup;
} }
if (!hardlink) {
err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
acl);
if (err)
goto out_cleanup;
err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
default_acl);
if (err)
goto out_cleanup;
}
if (!hardlink && S_ISDIR(stat->mode)) { if (!hardlink && S_ISDIR(stat->mode)) {
err = ovl_set_opaque(newdentry); err = ovl_set_opaque(newdentry);
...@@ -410,6 +460,10 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -410,6 +460,10 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
out_unlock: out_unlock:
unlock_rename(workdir, upperdir); unlock_rename(workdir, upperdir);
out: out:
if (!hardlink) {
posix_acl_release(acl);
posix_acl_release(default_acl);
}
return err; return err;
out_cleanup: out_cleanup:
......
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