1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6 #include <asm/byteorder.h>
7 #include <linux/fsverity.h>
8 #include <linux/slab.h>
9
10 #include "dsmm_developer.h"
11 #include "code_sign_elf.h"
12 #include "code_sign_log.h"
13 #include "verify_cert_chain.h"
14
15 #define SIGN_HEAD_SIZE (sizeof(sign_head_t))
16
parse_sign_head(sign_head_t * out,char * ptr)17 static void parse_sign_head(sign_head_t *out, char *ptr)
18 {
19 sign_head_t *tmp_data = (sign_head_t *) ptr;
20 /* magic and version are in byte represention */
21 strncpy(out->magic, tmp_data->magic, sizeof(tmp_data->magic));
22 strncpy(out->version, tmp_data->version, sizeof(tmp_data->version));
23 out->sign_data_size = le32_to_cpu(tmp_data->sign_data_size);
24 out->sign_block_num = le32_to_cpu(tmp_data->sign_block_num);
25 out->padding = le32_to_cpu(tmp_data->padding);
26 }
27
parse_tl_hdr(tl_header_t * out,char * ptr)28 static void parse_tl_hdr(tl_header_t *out, char *ptr)
29 {
30 tl_header_t *tmp_data = (tl_header_t *) ptr;
31 out->type = le32_to_cpu(tmp_data->type);
32 out->length = le32_to_cpu(tmp_data->length);
33 }
34
parse_block_hdr(block_hdr_t * out,char * ptr)35 static void parse_block_hdr(block_hdr_t *out, char *ptr)
36 {
37 block_hdr_t *tmp = (block_hdr_t *) ptr;
38 out->type = le32_to_cpu(tmp->type);
39 out->length = le32_to_cpu(tmp->length);
40 out->offset = le32_to_cpu(tmp->offset);
41 }
42
get_block_headers(sign_block_t * sign_block,char * sign_data_ptr)43 static int get_block_headers(sign_block_t *sign_block, char *sign_data_ptr)
44 {
45 /* parse all block headers */
46 for (int i = 0; i < sign_block->sign_head.sign_block_num; i++) {
47 block_hdr_t *tmp_block_hdr = (block_hdr_t *) (sign_data_ptr + sizeof(block_hdr_t) * i);
48 if (BLOCK_TYPE_CODE_SIGNING == le32_to_cpu(tmp_block_hdr->type)) {
49 parse_block_hdr(&sign_block->code_signing_block_hdr, sign_data_ptr + sizeof(block_hdr_t) * i);
50 } else if (BLOCK_TYPE_SIGNED_PROFILE == le32_to_cpu(tmp_block_hdr->type)) {
51 parse_block_hdr(&sign_block->profile_block_hdr, sign_data_ptr + sizeof(block_hdr_t) * i);
52 } else {
53 code_sign_log_error("block type invalid: %u", le32_to_cpu(tmp_block_hdr->type));
54 }
55 }
56 if (sign_block->code_signing_block_hdr.type != BLOCK_TYPE_CODE_SIGNING) {
57 code_sign_log_error("code signing block header not exist");
58 return -EINVAL;
59 }
60 if (sign_block->code_signing_block_hdr.offset + sizeof(tl_header_t) > sign_block->sign_head.sign_data_size) {
61 code_sign_log_error("code signing block offset invalid: %u", sign_block->code_signing_block_hdr.offset);
62 return -EINVAL;
63 }
64 return 0;
65 }
66
get_merkle_tree(sign_block_t * sign_block,char * sign_data_ptr)67 static int get_merkle_tree(sign_block_t *sign_block, char *sign_data_ptr)
68 {
69 parse_tl_hdr(&sign_block->merkle_tree_hdr, sign_data_ptr + sign_block->code_signing_block_hdr.offset);
70 if (sign_block->merkle_tree_hdr.type != TYPE_MERKLE_TREE) {
71 code_sign_log_error("merkle tree type invalid: %u", sign_block->merkle_tree_hdr.type);
72 return -EINVAL;
73 }
74 if (sign_block->merkle_tree_hdr.length + sizeof(tl_header_t)
75 > sign_block->sign_head.sign_data_size - sign_block->code_signing_block_hdr.offset - sizeof(tl_header_t)) {
76 code_sign_log_error("merkle tree data length invalid: %u", sign_block->merkle_tree_hdr.length);
77 return -EINVAL;
78 }
79 return 0;
80 }
81
get_fsverity_desc(sign_block_t * sign_block,char * sign_data_ptr)82 static int get_fsverity_desc(sign_block_t *sign_block, char *sign_data_ptr)
83 {
84 /* parse fsverity header and fsverity descriptor */
85 parse_tl_hdr(&sign_block->fsverity_desc_hdr, sign_data_ptr + sign_block->code_signing_block_hdr.offset
86 + sizeof(tl_header_t) + sign_block->merkle_tree_hdr.length);
87 if (sign_block->fsverity_desc_hdr.type != TYPE_FS_VERITY_DESC) {
88 code_sign_log_error("fsverity desc type invalid: %u", sign_block->fsverity_desc_hdr.type);
89 return -EINVAL;
90 }
91 if (sign_block->fsverity_desc_hdr.length
92 > sign_block->sign_head.sign_data_size - sign_block->code_signing_block_hdr.offset
93 - sizeof(tl_header_t) - sign_block->merkle_tree_hdr.length - sizeof(tl_header_t)) {
94 code_sign_log_error("fsverity desc length invalid: %u", sign_block->fsverity_desc_hdr.length);
95 return -EINVAL;
96 }
97
98 sign_block->fsverity_desc = (struct code_sign_descriptor *) (sign_data_ptr + sign_block->code_signing_block_hdr.offset
99 + sizeof(tl_header_t) + sign_block->merkle_tree_hdr.length
100 + sizeof(tl_header_t));
101 return 0;
102 }
103
validate_elf_source(const struct code_sign_descriptor * desc)104 static int validate_elf_source(const struct code_sign_descriptor *desc)
105 {
106 const u32 sig_size = le32_to_cpu(desc->sig_size);
107 int ret = 0;
108
109 code_sign_verify_certchain(desc->signature, sig_size, NULL, &ret);
110 if (ret < 0)
111 return ret;
112
113 if (ret <= DEBUG_CODE_START || ret >= DEBUG_CODE_END || ret == DEBUG_DEVELOPER_CODE) {
114 code_sign_log_error("invalid elf source, type: %d", ret);
115 return -EKEYREJECTED;
116 }
117 return 0;
118 }
119
enable_by_sign_head(struct file * fp,struct inode * inode,long long fsize,char * sign_head_ptr)120 static int enable_by_sign_head(struct file *fp, struct inode *inode, long long fsize, char *sign_head_ptr)
121 {
122 sign_block_t sign_block;
123 memset(&sign_block, 0, sizeof(sign_block));
124
125 parse_sign_head(&sign_block.sign_head, sign_head_ptr);
126 loff_t sign_data_start = fsize - SIGN_HEAD_SIZE - sign_block.sign_head.sign_data_size;
127
128 /* parse code signing block header */
129 char *sign_data_ptr = kzalloc(sign_block.sign_head.sign_data_size, GFP_KERNEL);
130 if (!sign_data_ptr) {
131 code_sign_log_error("kzalloc of sign_data_ptr failed");
132 return -ENOMEM;
133 }
134 ssize_t cnt = vfs_read(fp, sign_data_ptr, sign_block.sign_head.sign_data_size, &sign_data_start);
135 if (cnt != sign_block.sign_head.sign_data_size) {
136 code_sign_log_error("read sign data from file failed: read value %lu, expect %u bytes",
137 cnt, sign_block.sign_head.sign_data_size);
138 goto out;
139 }
140 int err = get_block_headers(&sign_block, sign_data_ptr);
141 if (err) {
142 code_sign_log_error("get_block_headers failed, err: %d", err);
143 goto out;
144 }
145
146 err = get_merkle_tree(&sign_block, sign_data_ptr);
147 if (err) {
148 code_sign_log_error("get_merkle_tree failed, err: %d", err);
149 goto out;
150 }
151
152 /* compute length of padding before merkle tree data */
153 merkle_tree_t merkle_tree;
154 merkle_tree.padding_length = sign_block.merkle_tree_hdr.length & ((1 << PAGE_SIZE_4K) - 1);
155 merkle_tree.merkle_tree_data = sign_data_ptr + sign_block.code_signing_block_hdr.offset
156 + sizeof(tl_header_t) + merkle_tree.padding_length;
157 merkle_tree.merkle_tree_length = sign_block.merkle_tree_hdr.length - merkle_tree.padding_length;
158 sign_block.merkle_tree = &merkle_tree;
159
160 err = get_fsverity_desc(&sign_block, sign_data_ptr);
161 if (err) {
162 code_sign_log_error("get_fsverity_desc failed, err: %d", err);
163 goto out;
164 }
165
166 err = mnt_want_write_file(fp);
167 if (err) /* -EROFS */
168 goto out;
169
170 err = deny_write_access(fp);
171 if (err) /* -ETXTBSY */
172 goto out_drop_write;
173
174 /* validate cert chain of elf signer */
175 err = validate_elf_source(sign_block.fsverity_desc);
176 if (err)
177 goto out;
178
179 /* fsverity_enable_with_descriptor in fs/verity/enable.c */
180 err = fsverity_enable_with_descriptor(fp, (void *)(sign_block.fsverity_desc), sign_block.fsverity_desc_hdr.length);
181 if (err) {
182 code_sign_log_error("fsverity_enable_with_descriptor returns err: %d", err);
183 goto out_allow_write_access;
184 }
185
186 filemap_write_and_wait(inode->i_mapping);
187 invalidate_inode_pages2(inode->i_mapping);
188
189 out_allow_write_access:
190 allow_write_access(fp);
191 out_drop_write:
192 mnt_drop_write_file(fp);
193 out:
194 kfree(sign_data_ptr);
195 return err;
196 }
197
elf_file_enable_fs_verity(struct file * file)198 int elf_file_enable_fs_verity(struct file *file)
199 {
200 /* developer mode */
201 if (get_developer_mode_state() != STATE_ON) {
202 code_sign_log_info("developer mode off, elf not allowed to execute");
203 return -EINVAL;
204 }
205 mm_segment_t fs;
206 char *path_buf = kzalloc(PATH_MAX, GFP_KERNEL);
207 if (!path_buf) {
208 code_sign_log_error("alloc mem for path_buf failed");
209 return -ENOMEM;
210 }
211 int err = 0;
212 char *real_path = file_path(file, path_buf, PATH_MAX - 1);
213 if (IS_ERR_OR_NULL(real_path)) {
214 code_sign_log_error("get file path failed");
215 err = -ENOENT;
216 goto release_path_buf_out;
217 }
218
219 struct file *fp = filp_open(real_path, O_RDONLY, 0);
220 if (IS_ERR(fp)) {
221 code_sign_log_error("filp_open failed");
222 err = PTR_ERR(fp);
223 goto release_path_buf_out;
224 }
225 struct inode *inode = file_inode(fp);
226 if (!inode) {
227 code_sign_log_error("file_inode failed");
228 err = -EFAULT;
229 goto filp_close_out;;
230 }
231
232 long long fsize = inode->i_size;
233 long long pos = 0;
234 if (fsize <= SIGN_HEAD_SIZE) {
235 code_sign_log_error("file size too small: %llu", fsize);
236 err = -EINVAL;
237 goto filp_close_out;
238 } else {
239 pos = fsize - SIGN_HEAD_SIZE;
240 }
241
242 char *sign_head_ptr = kzalloc(SIGN_HEAD_SIZE, GFP_KERNEL);
243 if (!sign_head_ptr) {
244 code_sign_log_error("kzalloc of sign_head_ptr failed");
245 err = -ENOMEM;
246 goto filp_close_out;
247 }
248
249 fs = get_fs();
250 set_fs(KERNEL_DS);
251
252 ssize_t cnt = vfs_read(fp, sign_head_ptr, SIGN_HEAD_SIZE, &pos);
253 if (cnt != SIGN_HEAD_SIZE) {
254 code_sign_log_error("read sign head from file failed: return value %lu, expect %u bytes",
255 cnt, SIGN_HEAD_SIZE);
256 err = -EFAULT;
257 goto release_sign_head_out;
258 }
259 sign_head_t *tmp_sign_head = (sign_head_t *)sign_head_ptr;
260
261 /* check magic string */
262 if (strncmp(tmp_sign_head->magic, SIGN_MAGIC_STR, sizeof(SIGN_MAGIC_STR) - 1) != 0) {
263 err = -EINVAL;
264 goto release_sign_head_out;
265 }
266 if (fsize < (SIGN_HEAD_SIZE + le32_to_cpu(tmp_sign_head->sign_data_size))) {
267 code_sign_log_error("sign data size invalid: %u", tmp_sign_head->sign_data_size);
268 err = -EINVAL;
269 goto release_sign_head_out;
270 }
271
272 err = enable_by_sign_head(fp, inode, fsize, sign_head_ptr);
273 if (err) {
274 code_sign_log_error("enable_by_sign_head err: %d", err);
275 goto release_sign_head_out;
276 }
277 code_sign_log_info("enable fsverity on file %s success", real_path);
278
279 release_sign_head_out:
280 kfree(sign_head_ptr);
281 set_fs(fs);
282 filp_close_out:
283 filp_close(fp, NULL);
284 release_path_buf_out:
285 kfree(path_buf);
286 return err;
287 }
288