Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1530be50 authored by Paul Lawrence's avatar Paul Lawrence
Browse files

ANDROID: Incremental fs: Add INCFS_IOC_PERMIT_FILL



Provide a securable way to open a file for filling

Test: incfs_test passes
Bug: 138149732
Signed-off-by: default avatarPaul Lawrence <paullawrence@google.com>
Change-Id: Ib4b6fd839ad30ce08e31121d19e2c0d7066d302f
parent 73e7d656
Loading
Loading
Loading
Loading
+60 −2
Original line number Diff line number Diff line
@@ -132,6 +132,11 @@ static const struct file_operations incfs_file_ops = {
	.compat_ioctl = dispatch_ioctl
};

enum FILL_PERMISSION {
	CANT_FILL = 0,
	CAN_FILL = 1,
};

static const struct file_operations incfs_pending_read_file_ops = {
	.read = pending_reads_read,
	.poll = pending_reads_poll,
@@ -1281,6 +1286,9 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg)
	if (!df)
		return -EBADF;

	if ((uintptr_t)f->private_data != CAN_FILL)
		return -EPERM;

	if (copy_from_user(&fill_blocks, usr_fill_blocks, sizeof(fill_blocks)))
		return -EFAULT;

@@ -1333,6 +1341,53 @@ static long ioctl_fill_blocks(struct file *f, void __user *arg)
	return i;
}

static long ioctl_permit_fill(struct file *f, void __user *arg)
{
	struct incfs_permit_fill __user *usr_permit_fill = arg;
	struct incfs_permit_fill permit_fill;
	long error = 0;
	struct file *file = 0;

	if (f->f_op != &incfs_pending_read_file_ops)
		return -EPERM;

	if (copy_from_user(&permit_fill, usr_permit_fill, sizeof(permit_fill)))
		return -EFAULT;

	file = fget(permit_fill.file_descriptor);
	if (IS_ERR(file))
		return PTR_ERR(file);

	if (file->f_op != &incfs_file_ops) {
		error = -EPERM;
		goto out;
	}

	if (file->f_inode->i_sb != f->f_inode->i_sb) {
		error = -EPERM;
		goto out;
	}

	switch ((uintptr_t)file->private_data) {
	case CANT_FILL:
		file->private_data = (void *)CAN_FILL;
		break;

	case CAN_FILL:
		pr_debug("CAN_FILL already set");
		break;

	default:
		pr_warn("Invalid file private data");
		error = -EFAULT;
		goto out;
	}

out:
	fput(file);
	return error;
}

static long ioctl_read_file_signature(struct file *f, void __user *arg)
{
	struct incfs_get_file_sig_args __user *args_usr_ptr = arg;
@@ -1390,6 +1445,8 @@ static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg)
		return ioctl_create_file(mi, (void __user *)arg);
	case INCFS_IOC_FILL_BLOCKS:
		return ioctl_fill_blocks(f, (void __user *)arg);
	case INCFS_IOC_PERMIT_FILL:
		return ioctl_permit_fill(f, (void __user *)arg);
	case INCFS_IOC_READ_FILE_SIGNATURE:
		return ioctl_read_file_signature(f, (void __user *)arg);
	default:
@@ -1820,9 +1877,10 @@ static int file_open(struct inode *inode, struct file *file)
		goto out;
	}

	if (S_ISREG(inode->i_mode))
	if (S_ISREG(inode->i_mode)) {
		err = make_inode_ready_for_data_ops(mi, inode, backing_file);
	else if (S_ISDIR(inode->i_mode)) {
		file->private_data = (void *)CANT_FILL;
	} else if (S_ISDIR(inode->i_mode)) {
		struct dir_file *dir = NULL;

		dir = incfs_open_dir_file(mi, backing_file);
+22 −1
Original line number Diff line number Diff line
@@ -51,13 +51,23 @@
	_IOR(INCFS_IOCTL_BASE_CODE, 31, struct incfs_get_file_sig_args)

/*
 * Fill in one or more data block
 * Fill in one or more data block. This may only be called on a handle
 * passed as a parameter to INCFS_IOC_PERMIT_FILLING
 *
 * Returns number of blocks filled in, or error if none were
 */
#define INCFS_IOC_FILL_BLOCKS                                                  \
	_IOR(INCFS_IOCTL_BASE_CODE, 32, struct incfs_fill_blocks)

/*
 * Permit INCFS_IOC_FILL_BLOCKS on the given file descriptor
 * May only be called on .pending_reads file
 *
 * Returns 0 on success or error
 */
#define INCFS_IOC_PERMIT_FILL                                                  \
	_IOW(INCFS_IOCTL_BASE_CODE, 33, struct incfs_permit_fill)

enum incfs_compression_alg {
	COMPRESSION_NONE = 0,
	COMPRESSION_LZ4 = 1
@@ -136,6 +146,17 @@ struct incfs_fill_blocks {
	__aligned_u64 fill_blocks;
};

/*
 * Permit INCFS_IOC_FILL_BLOCKS on the given file descriptor
 * May only be called on .pending_reads file
 *
 * Argument for INCFS_IOC_PERMIT_FILL
 */
struct incfs_permit_fill {
	/* File to permit fills on */
	__u32 file_descriptor;
};

enum incfs_hash_tree_algorithm {
	INCFS_HASH_TREE_NONE = 0,
	INCFS_HASH_TREE_SHA256 = 1
+61 −12
Original line number Diff line number Diff line
@@ -204,15 +204,43 @@ static char *get_index_filename(const char *mnt_dir, incfs_uuid_t id)
	return strdup(path);
}

int open_file_by_id(char *mnt_dir, incfs_uuid_t id)
int open_file_by_id(const char *mnt_dir, incfs_uuid_t id, bool use_ioctl)
{
	char *path = get_index_filename(mnt_dir, id);
	int cmd_fd = open_commands_file(mnt_dir);
	int fd = open(path, O_RDWR);
	struct incfs_permit_fill permit_fill = {
		.file_descriptor = fd,
	};
	int error = 0;

	free(path);
	if (fd < 0) {
		print_error("Can't open file by id.");
		error = -errno;
		goto out;
	}

	if (use_ioctl && ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) {
		print_error("Failed to call PERMIT_FILL");
		error = -errno;
		goto out;
	}

	if (ioctl(fd, INCFS_IOC_PERMIT_FILL, &permit_fill) != -1 ||
	    errno != EPERM) {
		print_error(
			"Successfully called PERMIT_FILL on non pending_read file");
		return -errno;
		goto out;
	}

out:
	free(path);
	close(cmd_fd);

	if (error) {
		close(fd);
		return error;
	}

	return fd;
@@ -258,12 +286,6 @@ static int emit_test_blocks(char *mnt_dir, struct test_file *file,
	int i = 0;
	int blocks_written = 0;

	fd = open_file_by_id(mnt_dir, file->id);
	if (fd <= 0) {
		error = -errno;
		goto out;
	}

	for (i = 0; i < block_count; i++) {
		int block_index = blocks[i];
		bool compress = (file->index + block_index) % 2 == 0;
@@ -315,6 +337,24 @@ static int emit_test_blocks(char *mnt_dir, struct test_file *file,
	}

	if (!error) {
		fd = open_file_by_id(mnt_dir, file->id, false);
		if (fd < 0) {
			error = -errno;
			goto out;
		}
		write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
		if (write_res >= 0) {
			ksft_print_msg("Wrote to file via normal fd error\n");
			error = -EPERM;
			goto out;
		}

		close(fd);
		fd = open_file_by_id(mnt_dir, file->id, true);
		if (fd < 0) {
			error = -errno;
			goto out;
		}
		write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
		if (write_res < 0)
			error = -errno;
@@ -706,7 +746,6 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file)
	int err;
	int i;
	int fd;
	char *file_path;
	struct incfs_fill_blocks fill_blocks = {
		.count = file->mtree_block_count,
	};
@@ -729,9 +768,7 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file)
		};
	}

	file_path  = concat_file_name(mount_dir, file->name);
	fd = open(file_path, O_RDWR);
	free(file_path);
	fd = open_file_by_id(mount_dir, file->id, false);
	if (fd < 0) {
		err = errno;
		goto failure;
@@ -739,7 +776,19 @@ static int load_hash_tree(const char *mount_dir, struct test_file *file)

	err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
	close(fd);
	if (err >= 0) {
		err = -EPERM;
		goto failure;
	}

	fd = open_file_by_id(mount_dir, file->id, true);
	if (fd < 0) {
		err = errno;
		goto failure;
	}

	err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
	close(fd);
	if (err < fill_blocks.count)
		err = errno;
	else {