1 // SPDX-License-Identifier: GPL-2.0-only
3 * Ioctl to read verity metadata
5 * Copyright 2021 Google LLC
8 #include "fsverity_private.h"
10 #include <linux/backing-dev.h>
11 #include <linux/highmem.h>
12 #include <linux/sched/signal.h>
13 #include <linux/uaccess.h>
15 static int fsverity_read_merkle_tree(struct inode
*inode
,
16 const struct fsverity_info
*vi
,
17 void __user
*buf
, u64 offset
, int length
)
19 const struct fsverity_operations
*vops
= inode
->i_sb
->s_vop
;
21 unsigned int offs_in_page
;
22 pgoff_t index
, last_index
;
26 end_offset
= min(offset
+ length
, vi
->tree_params
.tree_size
);
27 if (offset
>= end_offset
)
29 offs_in_page
= offset_in_page(offset
);
30 last_index
= (end_offset
- 1) >> PAGE_SHIFT
;
33 * Iterate through each Merkle tree page in the requested range and copy
34 * the requested portion to userspace. Note that the Merkle tree block
35 * size isn't important here, as we are returning a byte stream; i.e.,
36 * we can just work with pages even if the tree block size != PAGE_SIZE.
38 for (index
= offset
>> PAGE_SHIFT
; index
<= last_index
; index
++) {
39 unsigned long num_ra_pages
=
40 min_t(unsigned long, last_index
- index
+ 1,
41 inode
->i_sb
->s_bdi
->io_pages
);
42 unsigned int bytes_to_copy
= min_t(u64
, end_offset
- offset
,
43 PAGE_SIZE
- offs_in_page
);
47 page
= vops
->read_merkle_tree_page(inode
, index
, num_ra_pages
);
51 "Error %d reading Merkle tree page %lu",
56 virt
= kmap_local_page(page
);
57 if (copy_to_user(buf
, virt
+ offs_in_page
, bytes_to_copy
)) {
66 retval
+= bytes_to_copy
;
68 offset
+= bytes_to_copy
;
70 if (fatal_signal_pending(current
)) {
77 return retval
? retval
: err
;
80 /* Copy the requested portion of the buffer to userspace. */
81 static int fsverity_read_buffer(void __user
*dst
, u64 offset
, int length
,
82 const void *src
, size_t src_length
)
84 if (offset
>= src_length
)
89 length
= min_t(size_t, length
, src_length
);
91 if (copy_to_user(dst
, src
, length
))
97 static int fsverity_read_descriptor(struct inode
*inode
,
98 void __user
*buf
, u64 offset
, int length
)
100 struct fsverity_descriptor
*desc
;
104 res
= fsverity_get_descriptor(inode
, &desc
);
108 /* don't include the builtin signature */
109 desc_size
= offsetof(struct fsverity_descriptor
, signature
);
112 res
= fsverity_read_buffer(buf
, offset
, length
, desc
, desc_size
);
118 static int fsverity_read_signature(struct inode
*inode
,
119 void __user
*buf
, u64 offset
, int length
)
121 struct fsverity_descriptor
*desc
;
124 res
= fsverity_get_descriptor(inode
, &desc
);
128 if (desc
->sig_size
== 0) {
134 * Include only the builtin signature. fsverity_get_descriptor()
135 * already verified that sig_size is in-bounds.
137 res
= fsverity_read_buffer(buf
, offset
, length
, desc
->signature
,
138 le32_to_cpu(desc
->sig_size
));
145 * fsverity_ioctl_read_metadata() - read verity metadata from a file
146 * @filp: file to read the metadata from
147 * @uarg: user pointer to fsverity_read_metadata_arg
149 * Return: length read on success, 0 on EOF, -errno on failure
151 int fsverity_ioctl_read_metadata(struct file
*filp
, const void __user
*uarg
)
153 struct inode
*inode
= file_inode(filp
);
154 const struct fsverity_info
*vi
;
155 struct fsverity_read_metadata_arg arg
;
159 vi
= fsverity_get_info(inode
);
161 return -ENODATA
; /* not a verity file */
163 * Note that we don't have to explicitly check that the file is open for
164 * reading, since verity files can only be opened for reading.
167 if (copy_from_user(&arg
, uarg
, sizeof(arg
)))
173 /* offset + length must not overflow. */
174 if (arg
.offset
+ arg
.length
< arg
.offset
)
177 /* Ensure that the return value will fit in INT_MAX. */
178 length
= min_t(u64
, arg
.length
, INT_MAX
);
180 buf
= u64_to_user_ptr(arg
.buf_ptr
);
182 switch (arg
.metadata_type
) {
183 case FS_VERITY_METADATA_TYPE_MERKLE_TREE
:
184 return fsverity_read_merkle_tree(inode
, vi
, buf
, arg
.offset
,
186 case FS_VERITY_METADATA_TYPE_DESCRIPTOR
:
187 return fsverity_read_descriptor(inode
, buf
, arg
.offset
, length
);
188 case FS_VERITY_METADATA_TYPE_SIGNATURE
:
189 return fsverity_read_signature(inode
, buf
, arg
.offset
, length
);
194 EXPORT_SYMBOL_GPL(fsverity_ioctl_read_metadata
);