ovl: do operations on underlying file system in mounter's context

Given we are now doing checks both on overlay inode as well underlying
inode, we should be able to do checks and operations on underlying file
system using mounter's context.

So modify all operations to do checks/operations on underlying dentry/inode
in the context of mounter.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index f84492f..5becbaf 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -41,6 +41,7 @@
 {
 	int err;
 	struct dentry *upperdentry;
+	const struct cred *old_cred;
 
 	/*
 	 * Check for permissions before trying to copy-up.  This is redundant
@@ -84,7 +85,9 @@
 			attr->ia_valid &= ~ATTR_MODE;
 
 		inode_lock(upperdentry->d_inode);
+		old_cred = ovl_override_creds(dentry->d_sb);
 		err = notify_change(upperdentry, attr, NULL);
+		revert_creds(old_cred);
 		if (!err)
 			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
 		inode_unlock(upperdentry->d_inode);
@@ -102,9 +105,14 @@
 			 struct kstat *stat)
 {
 	struct path realpath;
+	const struct cred *old_cred;
+	int err;
 
 	ovl_path_real(dentry, &realpath);
-	return vfs_getattr(&realpath, stat);
+	old_cred = ovl_override_creds(dentry->d_sb);
+	err = vfs_getattr(&realpath, stat);
+	revert_creds(old_cred);
+	return err;
 }
 
 int ovl_permission(struct inode *inode, int mask)
@@ -188,6 +196,8 @@
 {
 	struct dentry *realdentry;
 	struct inode *realinode;
+	const struct cred *old_cred;
+	const char *p;
 
 	if (!dentry)
 		return ERR_PTR(-ECHILD);
@@ -198,13 +208,18 @@
 	if (WARN_ON(!realinode->i_op->get_link))
 		return ERR_PTR(-EPERM);
 
-	return realinode->i_op->get_link(realdentry, realinode, done);
+	old_cred = ovl_override_creds(dentry->d_sb);
+	p = realinode->i_op->get_link(realdentry, realinode, done);
+	revert_creds(old_cred);
+	return p;
 }
 
 static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
 {
 	struct path realpath;
 	struct inode *realinode;
+	const struct cred *old_cred;
+	int err;
 
 	ovl_path_real(dentry, &realpath);
 	realinode = realpath.dentry->d_inode;
@@ -214,10 +229,12 @@
 
 	touch_atime(&realpath);
 
-	return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+	old_cred = ovl_override_creds(dentry->d_sb);
+	err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
+	revert_creds(old_cred);
+	return err;
 }
 
-
 static bool ovl_is_private_xattr(const char *name)
 {
 	return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
@@ -229,6 +246,7 @@
 {
 	int err;
 	struct dentry *upperdentry;
+	const struct cred *old_cred;
 
 	err = ovl_want_write(dentry);
 	if (err)
@@ -243,7 +261,9 @@
 		goto out_drop_write;
 
 	upperdentry = ovl_dentry_upper(dentry);
+	old_cred = ovl_override_creds(dentry->d_sb);
 	err = vfs_setxattr(upperdentry, name, value, size, flags);
+	revert_creds(old_cred);
 
 out_drop_write:
 	ovl_drop_write(dentry);
@@ -255,11 +275,16 @@
 		     const char *name, void *value, size_t size)
 {
 	struct dentry *realdentry = ovl_dentry_real(dentry);
+	ssize_t res;
+	const struct cred *old_cred;
 
 	if (ovl_is_private_xattr(name))
 		return -ENODATA;
 
-	return vfs_getxattr(realdentry, name, value, size);
+	old_cred = ovl_override_creds(dentry->d_sb);
+	res = vfs_getxattr(realdentry, name, value, size);
+	revert_creds(old_cred);
+	return res;
 }
 
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
@@ -267,8 +292,11 @@
 	struct dentry *realdentry = ovl_dentry_real(dentry);
 	ssize_t res;
 	int off;
+	const struct cred *old_cred;
 
+	old_cred = ovl_override_creds(dentry->d_sb);
 	res = vfs_listxattr(realdentry, list, size);
+	revert_creds(old_cred);
 	if (res <= 0 || size == 0)
 		return res;
 
@@ -295,6 +323,7 @@
 	int err;
 	struct path realpath;
 	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
+	const struct cred *old_cred;
 
 	err = ovl_want_write(dentry);
 	if (err)
@@ -316,7 +345,9 @@
 		ovl_path_upper(dentry, &realpath);
 	}
 
+	old_cred = ovl_override_creds(dentry->d_sb);
 	err = vfs_removexattr(realpath.dentry, name);
+	revert_creds(old_cred);
 out_drop_write:
 	ovl_drop_write(dentry);
 out:
@@ -326,6 +357,8 @@
 struct posix_acl *ovl_get_acl(struct inode *inode, int type)
 {
 	struct inode *realinode = ovl_inode_real(inode);
+	const struct cred *old_cred;
+	struct posix_acl *acl;
 
 	if (!IS_POSIXACL(realinode))
 		return NULL;
@@ -333,7 +366,11 @@
 	if (!realinode->i_op->get_acl)
 		return NULL;
 
-	return realinode->i_op->get_acl(realinode, type);
+	old_cred = ovl_override_creds(inode->i_sb);
+	acl = realinode->i_op->get_acl(realinode, type);
+	revert_creds(old_cred);
+
+	return acl;
 }
 
 static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,