1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 
16 /* Skipping relabel path if define in ignore_cfg. */
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdbool.h>
22 
23 #include "ignore_path.h"
24 #include "callbacks.h"
25 
26 static g_system_config_loaded = false;
27 static g_vendor_config_loaded = false;
28 ignore_paths_t g_ignore_paths = {NULL, NULL};
29 
insert_ignore_path(ignore_path_node_t **paths_ptr, const char *line)30 ignore_path_node_t *insert_ignore_path(ignore_path_node_t **paths_ptr, const char *line)
31 {
32 	ignore_path_node_t *new_node = malloc(sizeof(ignore_path_node_t));
33 	if (new_node == NULL) {
34 		return NULL;
35 	}
36 	new_node->path = strdup(line);
37 	if (new_node->path == NULL) {
38 		free(new_node);
39 		return NULL;
40 	}
41 	new_node->next = *paths_ptr;
42 	*paths_ptr = new_node;
43 	return new_node;
44 }
45 
trim_newline(char *str)46 size_t trim_newline(char *str)
47 {
48 	size_t length = strlen(str);
49 	if (length == 0) {
50 		return 0;
51 	}
52 	if (str[length - 1] == '\n') {
53 		str[--length] = '\0';
54 	}
55 	if (length > 0 && str[length - 1] == '\r') {
56 		str[--length] = '\0';
57 	}
58 	return length;
59 }
60 
trim_suffix_and_get_path_info(char *line, size_t real_length)61 path_info_t trim_suffix_and_get_path_info(char *line, size_t real_length)
62 {
63 	path_info_t info;
64 	if (line[real_length - SLASH_SUFFIX_LEN] == '/') {
65 		info.paths_ptr = &g_ignore_paths.slash_suffix_paths;
66 		info.suffix_len = SLASH_SUFFIX_LEN;
67 	} else if (real_length > 1
68 				&& line[real_length - SLASH_SUFFIX_LEN] == '*'
69 				&& line[real_length - STAR_SUFFIX_LEN] == '/') {
70 		info.paths_ptr = &g_ignore_paths.star_suffix_paths;
71 		info.suffix_len = STAR_SUFFIX_LEN;
72 	} else {
73 		info.paths_ptr = NULL;
74 		info.suffix_len = 0;
75 	}
76 	if (info.paths_ptr != NULL) {
77 		line[real_length - info.suffix_len] = '\0';
78 	}
79 	return info;
80 }
81 
load_ignore_cfg_from_file(const char *cfg_path)82 bool load_ignore_cfg_from_file(const char *cfg_path)
83 {
84 	FILE *file = fopen(cfg_path, "r");
85 	if (file == NULL) {
86 		selinux_log(SELINUX_INFO, "Failed to open file: %s\n", cfg_path);
87 		return false;
88 	}
89 
90 	char *line = NULL;
91 	size_t len = 0;
92 	bool result = true;
93 	while (getline(&line, &len, file) != -1) {
94 		size_t real_length = trim_newline(line);
95 		if (real_length > 0) {
96 			path_info_t info = trim_suffix_and_get_path_info(line, real_length);
97 			if (info.paths_ptr == NULL) {
98 				continue;
99 			}
100 			line[real_length - info.suffix_len] = '\0';
101 			ignore_path_node_t *new_node = insert_ignore_path(info.paths_ptr, line);
102 			if (new_node == NULL) {
103 				selinux_log(SELINUX_ERROR, "Failed to allocate memory or duplicate string: %s\n", line);
104 				continue;
105 			}
106 		}
107 	}
108 
109 	if (fclose(file)) {
110 		selinux_log(SELINUX_ERROR, "Failed to close file: %s\n", strerror(errno));
111 	}
112 	free(line);
113 	return result;
114 }
115 
load_ignore_cfgnull116 bool load_ignore_cfg()
117 {
118 	if (g_system_config_loaded && g_vendor_config_loaded) {
119 		return true;
120 	}
121 	bool result = true;
122 	if (!g_system_config_loaded) {
123 		g_system_config_loaded = load_ignore_cfg_from_file(SYSTEM_IGNORE_CFG_PATH);
124 	}
125 	if (!g_vendor_config_loaded) {
126 		g_vendor_config_loaded = load_ignore_cfg_from_file(VENDOR_IGNORE_CFG_PATH);
127 	}
128 	if (!g_system_config_loaded || !g_vendor_config_loaded) {
129 		result = false;
130 	}
131 	return result;
132 }
133 
find_ignore_path(ignore_path_node_t *current, const char *path)134 static bool find_ignore_path(ignore_path_node_t *current, const char *path)
135 {
136 	while (current != NULL) {
137 		if (strcmp(path, current->path) == 0) {
138 			return true;
139 		}
140 		current = current->next;
141 	}
142 	return false;
143 }
144 
skip_ignore_relabel(const char *path)145 enum skip_type skip_ignore_relabel(const char *path)
146 {
147 	if (find_ignore_path(g_ignore_paths.slash_suffix_paths, path)) {
148 		return SKIP_SELF_SUB_DIR;
149 	}
150 	if (find_ignore_path(g_ignore_paths.star_suffix_paths, path)) {
151 		return SKIP_SUB_DIR;
152 	}
153 	return SKIP_NONE;
154 }
155 
free_ignore_list(ignore_path_node_t **list_ptr)156 void free_ignore_list(ignore_path_node_t **list_ptr)
157 {
158 	while (*list_ptr != NULL) {
159 		ignore_path_node_t *temp = *list_ptr;
160 		*list_ptr = (*list_ptr)->next;
161 		free(temp->path);
162 		free(temp);
163 	}
164 	*list_ptr = NULL;
165 }
166 
free_ignore_cfgnull167 void free_ignore_cfg()
168 {
169 	free_ignore_list(&g_ignore_paths.slash_suffix_paths);
170 	free_ignore_list(&g_ignore_paths.star_suffix_paths);
171 	g_system_config_loaded = false;
172 	g_vendor_config_loaded = false;
173 }
174