ANDROID: Incremental fs: Set credentials before reading/writing

Use same selinux scheme as incfs v2
Fix memory leak

Bug: 185490481
Test: incfs_test passes
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: I6058ddad9d43ba01b2eabd7d3c576f2cc9b42292
(cherry picked from commit 9c375ab8f20ea5d767a2e09ad6cb7df7db5bc4dc)
diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c
index 91592ba..2dbb97c 100644
--- a/fs/incfs/data_mgmt.c
+++ b/fs/incfs/data_mgmt.c
@@ -144,7 +144,7 @@
 	if (!S_ISREG(bf->f_inode->i_mode))
 		return ERR_PTR(-EBADF);
 
-	bfc = incfs_alloc_bfc(bf);
+	bfc = incfs_alloc_bfc(mi, bf);
 	if (IS_ERR(bfc))
 		return ERR_CAST(bfc);
 
@@ -198,6 +198,7 @@
 	for (i = 0; i < ARRAY_SIZE(df->df_segments); i++)
 		data_file_segment_destroy(&df->df_segments[i]);
 	incfs_free_bfc(df->df_backing_file_context);
+	kfree(df->df_signature);
 	kfree(df);
 }
 
@@ -386,8 +387,8 @@
 	schedule_delayed_work(&log->ml_wakeup_work, msecs_to_jiffies(16));
 }
 
-static int validate_hash_tree(struct file *bf, struct file *f, int block_index,
-			      struct mem_range data, u8 *buf)
+static int validate_hash_tree(struct backing_file_context *bfc, struct file *f,
+			      int block_index, struct mem_range data, u8 *buf)
 {
 	struct data_file *df = get_incfs_data_file(f);
 	u8 stored_digest[INCFS_MAX_HASH_SIZE] = {};
@@ -444,7 +445,7 @@
 		if (page)
 			put_page(page);
 
-		res = incfs_kread(bf, buf, INCFS_DATA_FILE_BLOCK_SIZE,
+		res = incfs_kread(bfc, buf, INCFS_DATA_FILE_BLOCK_SIZE,
 				  hash_block_offset[lvl] + sig->hash_offset);
 		if (res < 0)
 			return res;
@@ -917,7 +918,7 @@
 	ssize_t result;
 	size_t bytes_to_read;
 	struct mount_info *mi = NULL;
-	struct file *bf = NULL;
+	struct backing_file_context *bfc = NULL;
 	struct data_file_block block = {};
 	struct data_file *df = get_incfs_data_file(f);
 
@@ -928,7 +929,7 @@
 		return -ERANGE;
 
 	mi = df->df_mount_info;
-	bf = df->df_backing_file_context->bc_file;
+	bfc = df->df_backing_file_context;
 
 	result = wait_for_data_block(df, index, timeout_ms, &block);
 	if (result < 0)
@@ -937,20 +938,20 @@
 	pos = block.db_backing_file_data_offset;
 	if (block.db_comp_alg == COMPRESSION_NONE) {
 		bytes_to_read = min(dst.len, block.db_stored_size);
-		result = incfs_kread(bf, dst.data, bytes_to_read, pos);
+		result = incfs_kread(bfc, dst.data, bytes_to_read, pos);
 
 		/* Some data was read, but not enough */
 		if (result >= 0 && result != bytes_to_read)
 			result = -EIO;
 	} else {
 		bytes_to_read = min(tmp.len, block.db_stored_size);
-		result = incfs_kread(bf, tmp.data, bytes_to_read, pos);
+		result = incfs_kread(bfc, tmp.data, bytes_to_read, pos);
 		if (result == bytes_to_read) {
 			result =
 				decompress(range(tmp.data, bytes_to_read), dst);
 			if (result < 0) {
 				const char *name =
-					bf->f_path.dentry->d_name.name;
+				    bfc->bc_file->f_path.dentry->d_name.name;
 
 				pr_warn_once("incfs: Decompression error. %s",
 					     name);
@@ -962,7 +963,7 @@
 	}
 
 	if (result > 0) {
-		int err = validate_hash_tree(bf, f, index, dst, tmp.data);
+		int err = validate_hash_tree(bfc, f, index, dst, tmp.data);
 
 		if (err < 0)
 			result = err;
@@ -1025,14 +1026,13 @@
 unlock:
 	mutex_unlock(&segment->blockmap_mutex);
 	if (error)
-		pr_debug("incfs: %s %d error: %d\n", __func__,
-				block->block_index, error);
+		pr_debug("%d error: %d\n", block->block_index, error);
 	return error;
 }
 
 int incfs_read_file_signature(struct data_file *df, struct mem_range dst)
 {
-	struct file *bf = df->df_backing_file_context->bc_file;
+	struct backing_file_context *bfc = df->df_backing_file_context;
 	struct incfs_df_signature *sig;
 	int read_res = 0;
 
@@ -1046,7 +1046,7 @@
 	if (dst.len < sig->sig_size)
 		return -E2BIG;
 
-	read_res = incfs_kread(bf, dst.data, sig->sig_size, sig->sig_offset);
+	read_res = incfs_kread(bfc, dst.data, sig->sig_size, sig->sig_offset);
 
 	if (read_res < 0)
 		return read_res;
@@ -1168,7 +1168,7 @@
 		goto out;
 	}
 
-	read = incfs_kread(df->df_backing_file_context->bc_file, buf,
+	read = incfs_kread(df->df_backing_file_context, buf,
 			   signature->sig_size, signature->sig_offset);
 	if (read < 0) {
 		error = read;
diff --git a/fs/incfs/format.c b/fs/incfs/format.c
index c1e3c66..d7c557e 100644
--- a/fs/incfs/format.c
+++ b/fs/incfs/format.c
@@ -15,7 +15,8 @@
 #include "format.h"
 #include "data_mgmt.h"
 
-struct backing_file_context *incfs_alloc_bfc(struct file *backing_file)
+struct backing_file_context *incfs_alloc_bfc(struct mount_info *mi,
+					     struct file *backing_file)
 {
 	struct backing_file_context *result = NULL;
 
@@ -24,6 +25,7 @@
 		return ERR_PTR(-ENOMEM);
 
 	result->bc_file = get_file(backing_file);
+	result->bc_cred = mi->mi_owner;
 	mutex_init(&result->bc_mutex);
 	return result;
 }
@@ -116,7 +118,7 @@
 static int write_to_bf(struct backing_file_context *bfc, const void *buf,
 			size_t count, loff_t pos)
 {
-	ssize_t res = incfs_kwrite(bfc->bc_file, buf, count, pos);
+	ssize_t res = incfs_kwrite(bfc, buf, count, pos);
 
 	if (res < 0)
 		return res;
@@ -530,8 +532,7 @@
 	if (start_index < 0 || bm_base_off <= 0)
 		return -ENODATA;
 
-	result = incfs_kread(bfc->bc_file, entries, bytes_to_read,
-			     bm_entry_off);
+	result = incfs_kread(bfc, entries, bytes_to_read, bm_entry_off);
 	if (result < 0)
 		return result;
 	return result / sizeof(*entries);
@@ -547,8 +548,7 @@
 	if (!bfc || !first_md_off)
 		return -EFAULT;
 
-	LOCK_REQUIRED(bfc->bc_mutex);
-	bytes_read = incfs_kread(bfc->bc_file, &fh, sizeof(fh), 0);
+	bytes_read = incfs_kread(bfc, &fh, sizeof(fh), 0);
 	if (bytes_read < 0)
 		return bytes_read;
 
@@ -602,8 +602,8 @@
 		return -EPERM;
 
 	memset(&handler->md_buffer, 0, max_md_size);
-	bytes_read = incfs_kread(bfc->bc_file, &handler->md_buffer,
-				 max_md_size, handler->md_record_offset);
+	bytes_read = incfs_kread(bfc, &handler->md_buffer, max_md_size,
+				 handler->md_record_offset);
 	if (bytes_read < 0)
 		return bytes_read;
 	if (bytes_read < sizeof(*md_hdr))
@@ -679,12 +679,22 @@
 	return res;
 }
 
-ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos)
+ssize_t incfs_kread(struct backing_file_context *bfc, void *buf, size_t size,
+		    loff_t pos)
 {
-	return kernel_read(f, buf, size, &pos);
+	const struct cred *old_cred = override_creds(bfc->bc_cred);
+	int ret = kernel_read(bfc->bc_file, buf, size, &pos);
+
+	revert_creds(old_cred);
+	return ret;
 }
 
-ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos)
+ssize_t incfs_kwrite(struct backing_file_context *bfc, const void *buf,
+		     size_t size, loff_t pos)
 {
-	return kernel_write(f, buf, size, &pos);
+	const struct cred *old_cred = override_creds(bfc->bc_cred);
+	int ret = kernel_write(bfc->bc_file, buf, size, &pos);
+
+	revert_creds(old_cred);
+	return ret;
 }
diff --git a/fs/incfs/format.h b/fs/incfs/format.h
index 1a83349..a6d3aef 100644
--- a/fs/incfs/format.h
+++ b/fs/incfs/format.h
@@ -256,6 +256,13 @@
 	 * 0 means there are no metadata records.
 	 */
 	loff_t bc_last_md_record_offset;
+
+	/*
+	 * Credentials to set before reads/writes
+	 * Note that this is a pointer to the mount_info mi_owner field so
+	 * there is no need to get/put the creds
+	 */
+	const struct cred *bc_cred;
 };
 
 struct metadata_handler {
@@ -283,7 +290,9 @@
 loff_t incfs_get_end_offset(struct file *f);
 
 /* Backing file context management */
-struct backing_file_context *incfs_alloc_bfc(struct file *backing_file);
+struct mount_info;
+struct backing_file_context *incfs_alloc_bfc(struct mount_info *mi,
+					     struct file *backing_file);
 
 void incfs_free_bfc(struct backing_file_context *bfc);
 
@@ -334,7 +343,9 @@
 int incfs_read_next_metadata_record(struct backing_file_context *bfc,
 				    struct metadata_handler *handler);
 
-ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos);
-ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos);
+ssize_t incfs_kread(struct backing_file_context *bfc, void *buf, size_t size,
+		    loff_t pos);
+ssize_t incfs_kwrite(struct backing_file_context *bfc, const void *buf,
+		     size_t size, loff_t pos);
 
 #endif /* _INCFS_FORMAT_H */
diff --git a/fs/incfs/main.c b/fs/incfs/main.c
index d87817e8..5ee283a 100644
--- a/fs/incfs/main.c
+++ b/fs/incfs/main.c
@@ -28,8 +28,18 @@
 
 static struct kobj_attribute corefs_attr = __ATTR_RO(corefs);
 
+static ssize_t mounter_context_for_backing_rw_show(struct kobject *kobj,
+			  struct kobj_attribute *attr, char *buff)
+{
+	return snprintf(buff, PAGE_SIZE, "supported\n");
+}
+
+static struct kobj_attribute mounter_context_for_backing_rw_attr =
+	__ATTR_RO(mounter_context_for_backing_rw);
+
 static struct attribute *attributes[] = {
 	&corefs_attr.attr,
+	&mounter_context_for_backing_rw_attr.attr,
 	NULL,
 };
 
diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c
index b5ec4ed..346f528 100644
--- a/fs/incfs/vfs.c
+++ b/fs/incfs/vfs.c
@@ -900,14 +900,14 @@
 		.dentry = dentry
 	};
 	new_file = dentry_open(&path, O_RDWR | O_NOATIME | O_LARGEFILE,
-			       mi->mi_owner);
+			       current_cred());
 
 	if (IS_ERR(new_file)) {
 		error = PTR_ERR(new_file);
 		goto out;
 	}
 
-	bfc = incfs_alloc_bfc(new_file);
+	bfc = incfs_alloc_bfc(mi, new_file);
 	fput(new_file);
 	if (IS_ERR(bfc)) {
 		error = PTR_ERR(bfc);
@@ -1028,7 +1028,7 @@
 	if (dir_fd < 0)
 		return dir_fd;
 
-	dir_f = dentry_open(base_path, O_RDONLY | O_NOATIME, mi->mi_owner);
+	dir_f = dentry_open(base_path, O_RDONLY | O_NOATIME, current_cred());
 
 	if (IS_ERR(dir_f)) {
 		error = PTR_ERR(dir_f);
@@ -1906,10 +1906,13 @@
 	struct file *backing_file = NULL;
 	struct path backing_path = {};
 	int err = 0;
+	const struct cred *old_cred;
 
 	get_incfs_backing_path(file->f_path.dentry, &backing_path);
-	backing_file = dentry_open(
-		&backing_path, O_RDWR | O_NOATIME | O_LARGEFILE, mi->mi_owner);
+	old_cred = override_creds(mi->mi_owner);
+	backing_file = dentry_open(&backing_path,
+			O_RDWR | O_NOATIME | O_LARGEFILE, current_cred());
+	revert_creds(old_cred);
 	path_put(&backing_path);
 
 	if (IS_ERR(backing_file)) {