1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
4  */
5 #include <linux/string.h>
6 #include <linux/fcntl.h>
7 #include <linux/fs.h>
8 #include <linux/slab.h>
9 #include <linux/rwlock_types.h>
10 #include <linux/rwlock.h>
11 #include <linux/init.h>
12 #include <linux/moduleparam.h>
13 #include <linux/device-mapper.h>
14 #include <linux/kdev_t.h>
15 #include <linux/namei.h>
16 #include <linux/sched.h>
17 #include "mount.h"
18 #include "internal.h"
19 #include "exec_signature_info.h"
20 #include "xpm_report.h"
21 #include "xpm_log.h"
22 #include "code_sign_elf.h"
23 
24 #define VERITY_NODE_CACHE_LIMITS       10000
25 #define VERITY_NODE_CACHE_RECYCLE_NUM  200
26 
27 static DEFINE_RWLOCK(dm_verity_tree_lock);
28 static struct rb_root dm_verity_tree = RB_ROOT;
29 static int dm_verity_node_count;
30 static DEFINE_RWLOCK(fs_verity_tree_lock);
31 static struct rb_root fs_verity_tree = RB_ROOT;
32 static int fs_verity_node_count;
33 
34 struct verity_info {
35 	struct rb_root *root;
36 	rwlock_t *lock;
37 	int *node_count;
38 };
39 
40 static bool dm_verity_enable_check;
41 
42 #define DM_PARTITION_PATH_MAX	30
43 #define DM_VERITY_INVALID_DEV	((dev_t)-1)
44 
45 struct dm_partition {
46 	char path[DM_PARTITION_PATH_MAX];
47 	int len;
48 	dev_t s_dev;
49 };
50 
51 static struct dm_partition	dm_partition_table[] = {
52 	{ .path = "/",           .len = 1,  .s_dev = DM_VERITY_INVALID_DEV },
53 	{ .path = "/cust/",      .len = 6,  .s_dev = DM_VERITY_INVALID_DEV },
54 	{ .path = "/system/",    .len = 8,  .s_dev = DM_VERITY_INVALID_DEV },
55 	{ .path = "/vendor/",    .len = 8,  .s_dev = DM_VERITY_INVALID_DEV },
56 	{ .path = "/version/",   .len = 9,  .s_dev = DM_VERITY_INVALID_DEV },
57 	{ .path = "/preload/",   .len = 9,  .s_dev = DM_VERITY_INVALID_DEV },
58 	{ .path = "/sys_prod/",  .len = 10, .s_dev = DM_VERITY_INVALID_DEV },
59 	{ .path = "/chip_prod/", .len = 11, .s_dev = DM_VERITY_INVALID_DEV },
60 	{ .path = "/module_updata/",             .len = 15, .s_dev = DM_VERITY_INVALID_DEV },
61 	{ .path = "/vendor/modem/modem_vendor/", .len = 27, .s_dev = DM_VERITY_INVALID_DEV },
62 	{ .path = "/vendor/modem/modem_driver/", .len = 27, .s_dev = DM_VERITY_INVALID_DEV },
63 	{ .path = "/misc/",      .len = 6,  .s_dev = DM_VERITY_INVALID_DEV },
64 };
65 
66 static struct path	root_path;
67 
get_file_dev(struct file *file)68 static dev_t get_file_dev(struct file *file)
69 {
70 	struct super_block *sb;
71 	struct mount *mnt;
72 
73 	if (file->f_path.mnt == NULL)
74 		return DM_VERITY_INVALID_DEV;
75 
76 	mnt = container_of(file->f_path.mnt, struct mount, mnt);
77 	sb = mnt->mnt.mnt_sb;
78 	if (sb == NULL)
79 		return DM_VERITY_INVALID_DEV;
80 
81 	return sb->s_dev;
82 }
83 
get_partition_dev_form_mnt(const struct vfsmount *mnt)84 static dev_t get_partition_dev_form_mnt(const struct vfsmount *mnt)
85 {
86 	if (IS_ERR_OR_NULL(mnt) || IS_ERR_OR_NULL(mnt->mnt_sb))
87 		return DM_VERITY_INVALID_DEV;
88 	return mnt->mnt_sb->s_dev;
89 }
90 
get_root_partition_dev(struct path *root_path)91 static dev_t get_root_partition_dev(struct path *root_path)
92 {
93 	int ret;
94 	struct path path;
95 	struct path *mount_path = &path;
96 	dev_t s_dev;
97 
98 	if (root_path != NULL)
99 		mount_path = root_path;
100 	ret = kern_path("/", LOOKUP_DIRECTORY, mount_path);
101 	if (ret) {
102 		xpm_log_error("get / path failed");
103 		return DM_VERITY_INVALID_DEV;
104 	}
105 	s_dev = get_partition_dev_form_mnt(mount_path->mnt);
106 	if (s_dev == DM_VERITY_INVALID_DEV || root_path == NULL)
107 		path_put(mount_path);
108 	xpm_log_info("get / dev=%u:%u success", s_dev, MINOR(s_dev));
109 	return s_dev;
110 }
111 
get_dm_verity_partition_dev(const char *dir, struct path *root_path)112 static dev_t get_dm_verity_partition_dev(const char *dir, struct path *root_path)
113 {
114 	int ret;
115 	struct path path;
116 	dev_t s_dev;
117 
118 	ret = vfs_path_lookup(root_path->dentry, root_path->mnt, dir, LOOKUP_DIRECTORY, &path);
119 	if (ret) {
120 		xpm_log_error("get %s path failed", dir);
121 		return DM_VERITY_INVALID_DEV;
122 	}
123 	s_dev = get_partition_dev_form_mnt(path.mnt);
124 	path_put(&path);
125 	xpm_log_info("get %s dev=%u:%u success", dir, s_dev, MINOR(s_dev));
126 	return s_dev;
127 }
128 
find_partition_dev(struct file *file, dev_t s_dev)129 static bool find_partition_dev(struct file *file, dev_t s_dev)
130 {
131 	char *full_path = NULL;
132 	char path[PATH_MAX] = {0};
133 	struct dm_partition *dm_path;
134 	int i;
135 
136 	for (i = 1; i < sizeof(dm_partition_table) / sizeof(struct dm_partition); i++) {
137 		dm_path = &dm_partition_table[i];
138 		if (dm_path->s_dev != DM_VERITY_INVALID_DEV)
139 			continue;
140 
141 		if (full_path == NULL) {
142 			full_path = file_path(file, path, PATH_MAX-1);
143 			if (IS_ERR(full_path))
144 				return false;
145 		}
146 		if (strncmp(dm_path->path, full_path, dm_path->len) != 0)
147 			continue;
148 
149 		dm_path->s_dev = get_dm_verity_partition_dev(dm_path->path, &root_path);
150 		if (dm_path->s_dev == DM_VERITY_INVALID_DEV)
151 			return false;
152 		if (dm_path->s_dev == s_dev)
153 			return true;
154 		return false;
155 	}
156 
157 	return false;
158 }
159 
dm_verity_check_for_path(struct file *file)160 static bool dm_verity_check_for_path(struct file *file)
161 {
162 	static int system_startup_stage;
163 	struct dm_partition *dm_path;
164 	dev_t s_dev, root_dev;
165 	int i;
166 
167 	s_dev = get_file_dev(file);
168 	for (i = 0; i < sizeof(dm_partition_table) / sizeof(struct dm_partition); i++) {
169 		dm_path = &dm_partition_table[i];
170 		if (dm_path->s_dev == s_dev)
171 			return true;
172 	}
173 
174 	if (system_startup_stage)
175 		return find_partition_dev(file, s_dev);
176 
177 	if (task_pid_nr(current) == 1) {
178 		root_dev = get_root_partition_dev(NULL);
179 		if (root_dev != dm_partition_table[0].s_dev) {
180 			path_put(&root_path);
181 			dm_partition_table[0].s_dev = get_root_partition_dev(&root_path);
182 			for (i = 1; i < sizeof(dm_partition_table) / sizeof(struct dm_partition); i++)
183 				dm_partition_table[i].s_dev = DM_VERITY_INVALID_DEV;
184 			system_startup_stage = 1;
185 		}
186 	}
187 	return find_partition_dev(file, s_dev);
188 }
189 
190 #ifdef CONFIG_DM_VERITY
191 #define HVB_CMDLINE_VB_STATE	"ohos.boot.hvb.enable"
192 static bool dm_verity_enable;
193 
hvb_boot_param_cb(char *param, char *val, const char *unused, void *arg)194 static int hvb_boot_param_cb(char *param, char *val,
195 	const char *unused, void *arg)
196 {
197 	if (param == NULL || val == NULL)
198 		return 0;
199 
200 	if (strcmp(param, HVB_CMDLINE_VB_STATE) != 0)
201 		return 0;
202 
203 	if (strcmp(val, "true") == 0 || strcmp(val, "green") == 0)
204 		dm_verity_enable = true;
205 
206 	return 0;
207 }
208 
dm_verity_is_enable(void)209 static bool dm_verity_is_enable(void)
210 {
211 	char *cmdline;
212 
213 	if (dm_verity_enable || dm_verity_enable_check)
214 		return dm_verity_enable;
215 
216 	cmdline = kstrdup(saved_command_line, GFP_KERNEL);
217 	if (cmdline == NULL)
218 		return false;
219 
220 	parse_args("hvb.enable params", cmdline, NULL,
221 		0, 0, 0, NULL, &hvb_boot_param_cb);
222 	kfree(cmdline);
223 	dm_verity_enable_check = true;
224 	if (!dm_verity_enable) {
225 		dm_partition_table[0].s_dev = get_root_partition_dev(&root_path);
226 		report_init_event(DM_DISABLE);
227 	}
228 	return dm_verity_enable;
229 }
230 
dm_verity_check_for_mnt(struct file *file)231 static bool dm_verity_check_for_mnt(struct file *file)
232 {
233 	struct mapped_device *device;
234 
235 	device = dm_get_md(get_file_dev(file));
236 	if (device == NULL)
237 		return false;
238 
239 	dm_put(device);
240 	return true;
241 }
242 #endif
243 
is_dm_verity(struct file *file)244 static bool is_dm_verity(struct file *file)
245 {
246 #ifdef CONFIG_DM_VERITY
247 	if (dm_verity_is_enable())
248 		return dm_verity_check_for_mnt(file);
249 #endif
250 
251 	if (!dm_verity_enable_check) {
252 		dm_partition_table[0].s_dev = get_root_partition_dev(&root_path);
253 		dm_verity_enable_check = true;
254 		report_init_event(DM_DISABLE);
255 	}
256 	return dm_verity_check_for_path(file);
257 }
258 
259 #ifdef CONFIG_FS_VERITY
is_fs_verity(struct file *file)260 static bool is_fs_verity(struct file *file)
261 {
262 	struct inode *file_node;
263 
264 	file_node = file_inode(file);
265 	if (file_node == NULL)
266 		return false;
267 
268 	if (file_node->i_verity_info == NULL)
269 		return false;
270 
271 	return true;
272 }
273 #endif
274 
check_exec_file_is_verity(struct file *file, bool is_exec)275 static int check_exec_file_is_verity(struct file *file, bool is_exec)
276 {
277 #ifdef CONFIG_FS_VERITY
278 	if (is_fs_verity(file))
279 		return FILE_SIGNATURE_FS_VERITY;
280 #endif
281 
282 	if (is_dm_verity(file))
283 		return FILE_SIGNATURE_DM_VERITY;
284 
285 #ifdef CONFIG_SECURITY_CODE_SIGN
286 	if (is_exec && !elf_file_enable_fs_verity(file))
287 		return FILE_SIGNATURE_FS_VERITY;
288 #endif
289 
290 	return FILE_SIGNATURE_INVALID;
291 }
292 
rb_search_node(struct rb_root *root, uintptr_t file_inode)293 static struct exec_file_signature_info *rb_search_node(struct rb_root *root, uintptr_t file_inode)
294 {
295 	struct rb_node *node = root->rb_node;
296 	struct exec_file_signature_info *file_node;
297 
298 	while (node != NULL) {
299 		file_node = rb_entry(node, struct exec_file_signature_info, rb_node);
300 		if (file_inode < file_node->inode) {
301 			node = file_node->rb_node.rb_left;
302 		} else if (file_inode > file_node->inode) {
303 			node = file_node->rb_node.rb_right;
304 		} else {
305 			atomic_inc(&file_node->reference);
306 			return file_node;
307 		}
308 	}
309 	return NULL;
310 }
311 
rb_add_node(struct rb_root *root, int *node_count, struct exec_file_signature_info *node)312 static struct exec_file_signature_info *rb_add_node(struct rb_root *root, int *node_count,
313 	struct exec_file_signature_info *node)
314 {
315 	struct rb_node **p = &root->rb_node;
316 	struct rb_node *parent = NULL;
317 	struct exec_file_signature_info *file;
318 
319 	while (*p != NULL) {
320 		parent = *p;
321 		file = rb_entry(parent, struct exec_file_signature_info, rb_node);
322 		if (node->inode < file->inode) {
323 			p = &(*p)->rb_left;
324 		} else if (node->inode > file->inode) {
325 			p = &(*p)->rb_right;
326 		} else {
327 			atomic_inc(&file->reference);
328 			return file;
329 		}
330 	}
331 
332 	rb_link_node(&node->rb_node, parent, p);
333 	rb_insert_color(&node->rb_node, root);
334 	atomic_inc(&node->reference);
335 	(*node_count)++;
336 	return NULL;
337 }
338 
rb_erase_node(struct rb_root *root, int *node_count, struct exec_file_signature_info *node)339 static void rb_erase_node(struct rb_root *root, int *node_count,
340 	struct exec_file_signature_info *node)
341 {
342 	rb_erase(&node->rb_node, root);
343 	(*node_count)--;
344 }
345 
find_idle_nodes(struct rb_root *root, uintptr_t *ilde_nodes, int count)346 static int find_idle_nodes(struct rb_root *root, uintptr_t *ilde_nodes, int count)
347 {
348 	int i = 0;
349 	struct exec_file_signature_info *code_segment;
350 	struct rb_node *node;
351 
352 	for (node = rb_first(root); node != NULL && i < count; node = rb_next(node)) {
353 		code_segment = rb_entry(node, struct exec_file_signature_info, rb_node);
354 		if (atomic_read(&code_segment->reference) > 0)
355 			continue;
356 
357 		ilde_nodes[i++] = (uintptr_t)code_segment;
358 	}
359 	return i;
360 }
361 
clear_code_segment_info_cache(struct rb_root *root, int *node_count)362 static void clear_code_segment_info_cache(struct rb_root *root, int *node_count)
363 {
364 	struct exec_file_signature_info *code_segment_info;
365 	uintptr_t *code_segments;
366 	int i = 0;
367 	int count = VERITY_NODE_CACHE_RECYCLE_NUM;
368 
369 	code_segments = kcalloc(count, sizeof(uintptr_t), GFP_KERNEL);
370 	if (code_segments == NULL)
371 		return;
372 
373 	count = find_idle_nodes(root, code_segments, count);
374 	while (i < count) {
375 		code_segment_info = (struct exec_file_signature_info *)code_segments[i];
376 		rb_erase_node(root, node_count, code_segment_info);
377 		kfree(code_segment_info);
378 		i++;
379 	}
380 	kfree(code_segments);
381 }
382 
383 #ifdef CONFIG_SECURITY_XPM_DEBUG
test_elf_code_segment_info_size(struct rb_root *root)384 static size_t test_elf_code_segment_info_size(struct rb_root *root)
385 {
386 	size_t size = 0;
387 	struct exec_file_signature_info *file_node;
388 	struct rb_node *node;
389 
390 	for (node = rb_first(root); node != NULL; node = rb_next(node)) {
391 		file_node = rb_entry(node, struct exec_file_signature_info, rb_node);
392 		size += sizeof(struct exec_file_signature_info) +
393 				file_node->code_segment_count * sizeof(struct exec_segment_info);
394 	}
395 	return size;
396 }
397 
test_printf_code_segment_cache_size(void)398 static void test_printf_code_segment_cache_size(void)
399 {
400 	size_t cache_size = 0;
401 	int dm_count;
402 	int fs_count;
403 
404 	read_lock(&dm_verity_tree_lock);
405 	cache_size += test_elf_code_segment_info_size(&dm_verity_tree);
406 	dm_count = dm_verity_node_count;
407 	read_unlock(&dm_verity_tree_lock);
408 
409 	read_lock(&fs_verity_tree_lock);
410 	cache_size += test_elf_code_segment_info_size(&fs_verity_tree);
411 	fs_count = fs_verity_node_count;
412 	read_unlock(&fs_verity_tree_lock);
413 
414 	xpm_log_info("cache dm count=%d, fs count=%d, cache size=%d KB\n", dm_count, fs_count, cache_size / 1024);
415 }
416 
test_print_info(struct file *file, unsigned int type, const struct exec_file_signature_info *file_info)417 static void test_print_info(struct file *file, unsigned int type, const struct exec_file_signature_info *file_info)
418 {
419 	char *full_path;
420 	char path[PATH_MAX] = {0};
421 	static int code_segment_test_count = 100;
422 	int i;
423 
424 	code_segment_test_count--;
425 	if (code_segment_test_count > 0)
426 		return;
427 
428 	full_path = file_path(file, path, PATH_MAX - 1);
429 	if (IS_ERR(full_path))
430 		return;
431 
432 	for (i = 0; i < file_info->code_segment_count; i++)
433 		xpm_log_info("%s -> type: %s, info: offset=0x%llx size=0x%lx\n",
434 			full_path, type == FILE_SIGNATURE_DM_VERITY ? "dm" : "fs",
435 			file_info->code_segments->file_offset, file_info->code_segments->size);
436 
437 	code_segment_test_count = 100;
438 }
439 #endif
440 
rm_code_segment_info(void)441 static void rm_code_segment_info(void)
442 {
443 	if (dm_verity_node_count + fs_verity_node_count < VERITY_NODE_CACHE_LIMITS)
444 		return;
445 
446 #ifdef CONFIG_SECURITY_XPM_DEBUG
447 	test_printf_code_segment_cache_size();
448 #endif
449 
450 	if (dm_verity_node_count > fs_verity_node_count) {
451 		write_lock(&dm_verity_tree_lock);
452 		clear_code_segment_info_cache(&dm_verity_tree, &dm_verity_node_count);
453 		write_unlock(&dm_verity_tree_lock);
454 		return;
455 	}
456 
457 	write_lock(&fs_verity_tree_lock);
458 	clear_code_segment_info_cache(&fs_verity_tree, &fs_verity_node_count);
459 	write_unlock(&fs_verity_tree_lock);
460 }
461 
get_verity_info(int type, struct verity_info *verity)462 static int get_verity_info(int type, struct verity_info *verity)
463 {
464 	if (type == FILE_SIGNATURE_DM_VERITY) {
465 		verity->root = &dm_verity_tree;
466 		verity->lock = &dm_verity_tree_lock;
467 		verity->node_count = &dm_verity_node_count;
468 		return 0;
469 	}
470 
471 	if (type == FILE_SIGNATURE_FS_VERITY) {
472 		verity->lock = &fs_verity_tree_lock;
473 		verity->root = &fs_verity_tree;
474 		verity->node_count = &fs_verity_node_count;
475 		return 0;
476 	}
477 
478 	return -EINVAL;
479 }
480 
insert_new_signature_info(struct inode *file_node, int type, struct verity_info *verity, struct exec_file_signature_info *new_info, struct exec_file_signature_info **old_info)481 static void insert_new_signature_info(struct inode *file_node, int type,
482 	struct verity_info *verity, struct exec_file_signature_info *new_info, struct exec_file_signature_info **old_info)
483 {
484 	new_info->type = (unsigned int)type;
485 	new_info->inode = (uintptr_t)file_node;
486 	RB_CLEAR_NODE(&new_info->rb_node);
487 	if ((*old_info) != NULL) {
488 		write_lock(verity->lock);
489 		if ((*old_info) != NULL) {
490 			if (atomic_sub_return(1, &(*old_info)->reference) <= 0) {
491 				rb_erase_node(verity->root, verity->node_count, *old_info);
492 				(*old_info)->type |= FILE_SIGNATURE_DELETE;
493 				kfree(*old_info);
494 				*old_info = NULL;
495 			}
496 		}
497 		write_unlock(verity->lock);
498 	}
499 
500 	write_lock(verity->lock);
501 	*old_info = rb_add_node(verity->root, verity->node_count, new_info);
502 	write_unlock(verity->lock);
503 }
504 
get_elf_code_segment_info(struct file *file, bool is_exec, int type, struct exec_file_signature_info **code_segment_info)505 static int get_elf_code_segment_info(struct file *file, bool is_exec, int type,
506 	struct exec_file_signature_info **code_segment_info)
507 {
508 	int ret;
509 	struct verity_info verity;
510 	struct inode *file_node;
511 	struct exec_file_signature_info *new_info;
512 	struct exec_file_signature_info *old_info;
513 
514 	if (get_verity_info(type, &verity) < 0)
515 		return -EINVAL;
516 
517 	file_node = file_inode(file);
518 	if (file_node == NULL)
519 		return -EINVAL;
520 
521 	read_lock(verity.lock);
522 	old_info = rb_search_node(verity.root, (uintptr_t)file_node);
523 	read_unlock(verity.lock);
524 	if (old_info != NULL) {
525 		if (is_exec && old_info->code_segments == NULL)
526 			goto need_parse;
527 
528 		*code_segment_info = old_info;
529 		return 0;
530 	}
531 
532 need_parse:
533 	rm_code_segment_info();
534 
535 	if (!is_exec) {
536 		new_info = kzalloc(sizeof(struct exec_file_signature_info), GFP_KERNEL);
537 		if (new_info == NULL)
538 			return -ENOMEM;
539 	} else {
540 		ret = parse_elf_code_segment_info(file, &new_info);
541 		if (ret < 0) {
542 			report_file_event(FORMAT_UNDEF, file);
543 			return ret;
544 		}
545 #ifdef CONFIG_SECURITY_XPM_DEBUG
546 		test_print_info(file, type, new_info);
547 #endif
548 	}
549 
550 	insert_new_signature_info(file_node, type, &verity, new_info, &old_info);
551 	if (old_info != NULL) {
552 		kfree(new_info);
553 		new_info = old_info;
554 	}
555 	*code_segment_info = new_info;
556 	return 0;
557 }
558 
get_exec_file_signature_info(struct file *file, bool is_exec, struct exec_file_signature_info **info_ptr)559 int get_exec_file_signature_info(struct file *file, bool is_exec,
560 	struct exec_file_signature_info **info_ptr)
561 {
562 	int type;
563 
564 	if (file == NULL || info_ptr == NULL)
565 		return -EINVAL;
566 
567 	type = check_exec_file_is_verity(file, is_exec);
568 	return get_elf_code_segment_info(file, is_exec, type, info_ptr);
569 }
570 
put_exec_file_signature_info(struct exec_file_signature_info *exec_info)571 int put_exec_file_signature_info(struct exec_file_signature_info *exec_info)
572 {
573 	if ((exec_info == NULL) ||
574 		!exec_file_signature_is_verity(exec_info))
575 		return -EINVAL;
576 
577 	if (atomic_sub_return(1, &exec_info->reference) <= 0 &&
578 		exec_file_signature_is_delete(exec_info))
579 		kfree(exec_info);
580 	return 0;
581 }
582 
elf_code_segment_info_delete(struct rb_root *root, int *node_count, struct inode *file_node)583 static struct exec_file_signature_info *elf_code_segment_info_delete(struct rb_root *root,
584 	int *node_count, struct inode *file_node)
585 {
586 	struct exec_file_signature_info *signature_info;
587 
588 	signature_info = rb_search_node(root, (uintptr_t)file_node);
589 	if (signature_info != NULL) {
590 		rb_erase_node(root, node_count, signature_info);
591 		if (atomic_sub_return(1, &signature_info->reference) > 0)
592 			signature_info->type |= FILE_SIGNATURE_DELETE;
593 		else
594 			kfree(signature_info);
595 	}
596 	return signature_info;
597 }
598 
delete_exec_file_signature_info(struct inode *file_node)599 void delete_exec_file_signature_info(struct inode *file_node)
600 {
601 	struct exec_file_signature_info *signature_info;
602 
603 	if (file_node == NULL)
604 		return;
605 
606 	write_lock(&fs_verity_tree_lock);
607 	signature_info = elf_code_segment_info_delete(&fs_verity_tree, &fs_verity_node_count, file_node);
608 	write_unlock(&fs_verity_tree_lock);
609 	if (signature_info != NULL)
610 		return;
611 
612 	write_lock(&dm_verity_tree_lock);
613 	signature_info = elf_code_segment_info_delete(&dm_verity_tree, &dm_verity_node_count, file_node);
614 	write_unlock(&dm_verity_tree_lock);
615 }
616