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