Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Ioctl to read verity metadata
0004  *
0005  * Copyright 2021 Google LLC
0006  */
0007 
0008 #include "fsverity_private.h"
0009 
0010 #include <linux/backing-dev.h>
0011 #include <linux/highmem.h>
0012 #include <linux/sched/signal.h>
0013 #include <linux/uaccess.h>
0014 
0015 static int fsverity_read_merkle_tree(struct inode *inode,
0016                      const struct fsverity_info *vi,
0017                      void __user *buf, u64 offset, int length)
0018 {
0019     const struct fsverity_operations *vops = inode->i_sb->s_vop;
0020     u64 end_offset;
0021     unsigned int offs_in_page;
0022     pgoff_t index, last_index;
0023     int retval = 0;
0024     int err = 0;
0025 
0026     end_offset = min(offset + length, vi->tree_params.tree_size);
0027     if (offset >= end_offset)
0028         return 0;
0029     offs_in_page = offset_in_page(offset);
0030     last_index = (end_offset - 1) >> PAGE_SHIFT;
0031 
0032     /*
0033      * Iterate through each Merkle tree page in the requested range and copy
0034      * the requested portion to userspace.  Note that the Merkle tree block
0035      * size isn't important here, as we are returning a byte stream; i.e.,
0036      * we can just work with pages even if the tree block size != PAGE_SIZE.
0037      */
0038     for (index = offset >> PAGE_SHIFT; index <= last_index; index++) {
0039         unsigned long num_ra_pages =
0040             min_t(unsigned long, last_index - index + 1,
0041                   inode->i_sb->s_bdi->io_pages);
0042         unsigned int bytes_to_copy = min_t(u64, end_offset - offset,
0043                            PAGE_SIZE - offs_in_page);
0044         struct page *page;
0045         const void *virt;
0046 
0047         page = vops->read_merkle_tree_page(inode, index, num_ra_pages);
0048         if (IS_ERR(page)) {
0049             err = PTR_ERR(page);
0050             fsverity_err(inode,
0051                      "Error %d reading Merkle tree page %lu",
0052                      err, index);
0053             break;
0054         }
0055 
0056         virt = kmap(page);
0057         if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) {
0058             kunmap(page);
0059             put_page(page);
0060             err = -EFAULT;
0061             break;
0062         }
0063         kunmap(page);
0064         put_page(page);
0065 
0066         retval += bytes_to_copy;
0067         buf += bytes_to_copy;
0068         offset += bytes_to_copy;
0069 
0070         if (fatal_signal_pending(current))  {
0071             err = -EINTR;
0072             break;
0073         }
0074         cond_resched();
0075         offs_in_page = 0;
0076     }
0077     return retval ? retval : err;
0078 }
0079 
0080 /* Copy the requested portion of the buffer to userspace. */
0081 static int fsverity_read_buffer(void __user *dst, u64 offset, int length,
0082                 const void *src, size_t src_length)
0083 {
0084     if (offset >= src_length)
0085         return 0;
0086     src += offset;
0087     src_length -= offset;
0088 
0089     length = min_t(size_t, length, src_length);
0090 
0091     if (copy_to_user(dst, src, length))
0092         return -EFAULT;
0093 
0094     return length;
0095 }
0096 
0097 static int fsverity_read_descriptor(struct inode *inode,
0098                     void __user *buf, u64 offset, int length)
0099 {
0100     struct fsverity_descriptor *desc;
0101     size_t desc_size;
0102     int res;
0103 
0104     res = fsverity_get_descriptor(inode, &desc);
0105     if (res)
0106         return res;
0107 
0108     /* don't include the signature */
0109     desc_size = offsetof(struct fsverity_descriptor, signature);
0110     desc->sig_size = 0;
0111 
0112     res = fsverity_read_buffer(buf, offset, length, desc, desc_size);
0113 
0114     kfree(desc);
0115     return res;
0116 }
0117 
0118 static int fsverity_read_signature(struct inode *inode,
0119                    void __user *buf, u64 offset, int length)
0120 {
0121     struct fsverity_descriptor *desc;
0122     int res;
0123 
0124     res = fsverity_get_descriptor(inode, &desc);
0125     if (res)
0126         return res;
0127 
0128     if (desc->sig_size == 0) {
0129         res = -ENODATA;
0130         goto out;
0131     }
0132 
0133     /*
0134      * Include only the signature.  Note that fsverity_get_descriptor()
0135      * already verified that sig_size is in-bounds.
0136      */
0137     res = fsverity_read_buffer(buf, offset, length, desc->signature,
0138                    le32_to_cpu(desc->sig_size));
0139 out:
0140     kfree(desc);
0141     return res;
0142 }
0143 
0144 /**
0145  * fsverity_ioctl_read_metadata() - read verity metadata from a file
0146  * @filp: file to read the metadata from
0147  * @uarg: user pointer to fsverity_read_metadata_arg
0148  *
0149  * Return: length read on success, 0 on EOF, -errno on failure
0150  */
0151 int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg)
0152 {
0153     struct inode *inode = file_inode(filp);
0154     const struct fsverity_info *vi;
0155     struct fsverity_read_metadata_arg arg;
0156     int length;
0157     void __user *buf;
0158 
0159     vi = fsverity_get_info(inode);
0160     if (!vi)
0161         return -ENODATA; /* not a verity file */
0162     /*
0163      * Note that we don't have to explicitly check that the file is open for
0164      * reading, since verity files can only be opened for reading.
0165      */
0166 
0167     if (copy_from_user(&arg, uarg, sizeof(arg)))
0168         return -EFAULT;
0169 
0170     if (arg.__reserved)
0171         return -EINVAL;
0172 
0173     /* offset + length must not overflow. */
0174     if (arg.offset + arg.length < arg.offset)
0175         return -EINVAL;
0176 
0177     /* Ensure that the return value will fit in INT_MAX. */
0178     length = min_t(u64, arg.length, INT_MAX);
0179 
0180     buf = u64_to_user_ptr(arg.buf_ptr);
0181 
0182     switch (arg.metadata_type) {
0183     case FS_VERITY_METADATA_TYPE_MERKLE_TREE:
0184         return fsverity_read_merkle_tree(inode, vi, buf, arg.offset,
0185                          length);
0186     case FS_VERITY_METADATA_TYPE_DESCRIPTOR:
0187         return fsverity_read_descriptor(inode, buf, arg.offset, length);
0188     case FS_VERITY_METADATA_TYPE_SIGNATURE:
0189         return fsverity_read_signature(inode, buf, arg.offset, length);
0190     default:
0191         return -EINVAL;
0192     }
0193 }
0194 EXPORT_SYMBOL_GPL(fsverity_ioctl_read_metadata);