VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   1) // SPDX-License-Identifier: GPL-2.0-only
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   2) /*
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   3)  * Ioctl to read verity metadata
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   4)  *
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   5)  * Copyright 2021 Google LLC
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   6)  */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   7) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   8) #include "fsverity_private.h"
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800   9) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  10) #include <linux/backing-dev.h>
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  11) #include <linux/highmem.h>
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  12) #include <linux/sched/signal.h>
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800  13) #include <linux/uaccess.h>
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800  14) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  15) static int fsverity_read_merkle_tree(struct inode *inode,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  16) 				     const struct fsverity_info *vi,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  17) 				     void __user *buf, u64 offset, int length)
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  18) {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  19) 	const struct fsverity_operations *vops = inode->i_sb->s_vop;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  20) 	u64 end_offset;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  21) 	unsigned int offs_in_page;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  22) 	pgoff_t index, last_index;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  23) 	int retval = 0;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  24) 	int err = 0;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  25) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  26) 	end_offset = min(offset + length, vi->tree_params.tree_size);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  27) 	if (offset >= end_offset)
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  28) 		return 0;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  29) 	offs_in_page = offset_in_page(offset);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  30) 	last_index = (end_offset - 1) >> PAGE_SHIFT;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  31) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  32) 	/*
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  33) 	 * Iterate through each Merkle tree page in the requested range and copy
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  34) 	 * the requested portion to userspace.  Note that the Merkle tree block
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  35) 	 * size isn't important here, as we are returning a byte stream; i.e.,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  36) 	 * we can just work with pages even if the tree block size != PAGE_SIZE.
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  37) 	 */
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  38) 	for (index = offset >> PAGE_SHIFT; index <= last_index; index++) {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  39) 		unsigned long num_ra_pages =
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  40) 			min_t(unsigned long, last_index - index + 1,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  41) 			      inode->i_sb->s_bdi->io_pages);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  42) 		unsigned int bytes_to_copy = min_t(u64, end_offset - offset,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  43) 						   PAGE_SIZE - offs_in_page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  44) 		struct page *page;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  45) 		const void *virt;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  46) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  47) 		page = vops->read_merkle_tree_page(inode, index, num_ra_pages);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  48) 		if (IS_ERR(page)) {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  49) 			err = PTR_ERR(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  50) 			fsverity_err(inode,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  51) 				     "Error %d reading Merkle tree page %lu",
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  52) 				     err, index);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  53) 			break;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  54) 		}
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  55) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  56) 		virt = kmap(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  57) 		if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  58) 			kunmap(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  59) 			put_page(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  60) 			err = -EFAULT;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  61) 			break;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  62) 		}
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  63) 		kunmap(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  64) 		put_page(page);
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  65) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  66) 		retval += bytes_to_copy;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  67) 		buf += bytes_to_copy;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  68) 		offset += bytes_to_copy;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  69) 
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  70) 		if (fatal_signal_pending(current))  {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  71) 			err = -EINTR;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  72) 			break;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  73) 		}
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  74) 		cond_resched();
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  75) 		offs_in_page = 0;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  76) 	}
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  77) 	return retval ? retval : err;
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800  78) }
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  79) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  80) /* Copy the requested portion of the buffer to userspace. */
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  81) static int fsverity_read_buffer(void __user *dst, u64 offset, int length,
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  82) 				const void *src, size_t src_length)
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  83) {
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  84) 	if (offset >= src_length)
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  85) 		return 0;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  86) 	src += offset;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  87) 	src_length -= offset;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  88) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  89) 	length = min_t(size_t, length, src_length);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  90) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  91) 	if (copy_to_user(dst, src, length))
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  92) 		return -EFAULT;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  93) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  94) 	return length;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  95) }
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  96) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  97) static int fsverity_read_descriptor(struct inode *inode,
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  98) 				    void __user *buf, u64 offset, int length)
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800  99) {
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 100) 	struct fsverity_descriptor *desc;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 101) 	size_t desc_size;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 102) 	int res;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 103) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 104) 	res = fsverity_get_descriptor(inode, &desc, &desc_size);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 105) 	if (res)
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 106) 		return res;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 107) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 108) 	/* don't include the signature */
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 109) 	desc_size = offsetof(struct fsverity_descriptor, signature);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 110) 	desc->sig_size = 0;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 111) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 112) 	res = fsverity_read_buffer(buf, offset, length, desc, desc_size);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 113) 
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 114) 	kfree(desc);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 115) 	return res;
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 116) }
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 117) 
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 118) static int fsverity_read_signature(struct inode *inode,
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 119) 				   void __user *buf, u64 offset, int length)
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 120) {
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 121) 	struct fsverity_descriptor *desc;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 122) 	size_t desc_size;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 123) 	int res;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 124) 
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 125) 	res = fsverity_get_descriptor(inode, &desc, &desc_size);
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 126) 	if (res)
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 127) 		return res;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 128) 
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 129) 	if (desc->sig_size == 0) {
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 130) 		res = -ENODATA;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 131) 		goto out;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 132) 	}
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 133) 
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 134) 	/*
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 135) 	 * Include only the signature.  Note that fsverity_get_descriptor()
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 136) 	 * already verified that sig_size is in-bounds.
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 137) 	 */
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 138) 	res = fsverity_read_buffer(buf, offset, length, desc->signature,
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 139) 				   le32_to_cpu(desc->sig_size));
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 140) out:
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 141) 	kfree(desc);
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 142) 	return res;
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 143) }
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 144) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 145) /**
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 146)  * fsverity_ioctl_read_metadata() - read verity metadata from a file
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 147)  * @filp: file to read the metadata from
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 148)  * @uarg: user pointer to fsverity_read_metadata_arg
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 149)  *
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 150)  * Return: length read on success, 0 on EOF, -errno on failure
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 151)  */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 152) int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg)
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 153) {
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 154) 	struct inode *inode = file_inode(filp);
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 155) 	const struct fsverity_info *vi;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 156) 	struct fsverity_read_metadata_arg arg;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 157) 	int length;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 158) 	void __user *buf;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 159) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 160) 	vi = fsverity_get_info(inode);
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 161) 	if (!vi)
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 162) 		return -ENODATA; /* not a verity file */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 163) 	/*
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 164) 	 * Note that we don't have to explicitly check that the file is open for
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 165) 	 * reading, since verity files can only be opened for reading.
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 166) 	 */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 167) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 168) 	if (copy_from_user(&arg, uarg, sizeof(arg)))
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 169) 		return -EFAULT;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 170) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 171) 	if (arg.__reserved)
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 172) 		return -EINVAL;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 173) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 174) 	/* offset + length must not overflow. */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 175) 	if (arg.offset + arg.length < arg.offset)
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 176) 		return -EINVAL;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 177) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 178) 	/* Ensure that the return value will fit in INT_MAX. */
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 179) 	length = min_t(u64, arg.length, INT_MAX);
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 180) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 181) 	buf = u64_to_user_ptr(arg.buf_ptr);
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 182) 
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 183) 	switch (arg.metadata_type) {
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800 184) 	case FS_VERITY_METADATA_TYPE_MERKLE_TREE:
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800 185) 		return fsverity_read_merkle_tree(inode, vi, buf, arg.offset,
622699cfe6ec5 (Eric Biggers 2021-01-15 10:18:17 -0800 186) 						 length);
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 187) 	case FS_VERITY_METADATA_TYPE_DESCRIPTOR:
947191ac8caba (Eric Biggers 2021-01-15 10:18:18 -0800 188) 		return fsverity_read_descriptor(inode, buf, arg.offset, length);
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 189) 	case FS_VERITY_METADATA_TYPE_SIGNATURE:
07c99001312cb (Eric Biggers 2021-01-15 10:18:19 -0800 190) 		return fsverity_read_signature(inode, buf, arg.offset, length);
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 191) 	default:
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 192) 		return -EINVAL;
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 193) 	}
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 194) }
e17fe6579de02 (Eric Biggers 2021-01-15 10:18:16 -0800 195) EXPORT_SYMBOL_GPL(fsverity_ioctl_read_metadata);