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