Commit 66dbfabf authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: stack fileattr ops



Add stacking for the fileattr operations.

Add hack for calling security_file_ioctl() for now.  Probably better to
have a pair of specific hooks for these operations.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 97e2dee9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1301,4 +1301,6 @@ const struct inode_operations ovl_dir_inode_operations = {
	.listxattr	= ovl_listxattr,
	.get_acl	= ovl_get_acl,
	.update_time	= ovl_update_time,
	.fileattr_get	= ovl_fileattr_get,
	.fileattr_set	= ovl_fileattr_set,
};
+77 −0
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
#include <linux/posix_acl.h>
#include <linux/ratelimit.h>
#include <linux/fiemap.h>
#include <linux/fileattr.h>
#include <linux/security.h>
#include "overlayfs.h"


@@ -500,6 +502,79 @@ static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
	return err;
}

/*
 * Work around the fact that security_file_ioctl() takes a file argument.
 * Introducing security_inode_fileattr_get/set() hooks would solve this issue
 * properly.
 */
static int ovl_security_fileattr(struct dentry *dentry, struct fileattr *fa,
				 bool set)
{
	struct path realpath;
	struct file *file;
	unsigned int cmd;
	int err;

	ovl_path_real(dentry, &realpath);
	file = dentry_open(&realpath, O_RDONLY, current_cred());
	if (IS_ERR(file))
		return PTR_ERR(file);

	if (set)
		cmd = fa->fsx_valid ? FS_IOC_FSSETXATTR : FS_IOC_SETFLAGS;
	else
		cmd = fa->fsx_valid ? FS_IOC_FSGETXATTR : FS_IOC_GETFLAGS;

	err = security_file_ioctl(file, cmd, 0);
	fput(file);

	return err;
}

int ovl_fileattr_set(struct user_namespace *mnt_userns,
		     struct dentry *dentry, struct fileattr *fa)
{
	struct inode *inode = d_inode(dentry);
	struct dentry *upperdentry;
	const struct cred *old_cred;
	int err;

	err = ovl_want_write(dentry);
	if (err)
		goto out;

	err = ovl_copy_up(dentry);
	if (!err) {
		upperdentry = ovl_dentry_upper(dentry);

		old_cred = ovl_override_creds(inode->i_sb);
		err = ovl_security_fileattr(dentry, fa, true);
		if (!err)
			err = vfs_fileattr_set(&init_user_ns, upperdentry, fa);
		revert_creds(old_cred);
		ovl_copyflags(ovl_inode_real(inode), inode);
	}
	ovl_drop_write(dentry);
out:
	return err;
}

int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
	struct inode *inode = d_inode(dentry);
	struct dentry *realdentry = ovl_dentry_real(dentry);
	const struct cred *old_cred;
	int err;

	old_cred = ovl_override_creds(inode->i_sb);
	err = ovl_security_fileattr(dentry, fa, false);
	if (!err)
		err = vfs_fileattr_get(realdentry, fa);
	revert_creds(old_cred);

	return err;
}

static const struct inode_operations ovl_file_inode_operations = {
	.setattr	= ovl_setattr,
	.permission	= ovl_permission,
@@ -508,6 +583,8 @@ static const struct inode_operations ovl_file_inode_operations = {
	.get_acl	= ovl_get_acl,
	.update_time	= ovl_update_time,
	.fiemap		= ovl_fiemap,
	.fileattr_get	= ovl_fileattr_get,
	.fileattr_set	= ovl_fileattr_set,
};

static const struct inode_operations ovl_symlink_inode_operations = {
+3 −0
Original line number Diff line number Diff line
@@ -521,6 +521,9 @@ int __init ovl_aio_request_cache_init(void);
void ovl_aio_request_cache_destroy(void);
long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa);
int ovl_fileattr_set(struct user_namespace *mnt_userns,
		     struct dentry *dentry, struct fileattr *fa);

/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);