Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "chain.h"
7 :
8 : #include <errno.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include "core/dump.h"
13 : #include "core/helper.h"
14 : #include "core/hook.h"
15 : #include "core/list.h"
16 : #include "core/logger.h"
17 : #include "core/marsh.h"
18 : #include "core/rule.h"
19 : #include "core/set.h"
20 : #include "core/verdict.h"
21 :
22 20 : int bf_chain_new(struct bf_chain **chain, const char *name, enum bf_hook hook,
23 : enum bf_verdict policy, bf_list *sets, bf_list *rules)
24 : {
25 16 : _free_bf_chain_ struct bf_chain *_chain = NULL;
26 : size_t ridx = 0;
27 :
28 20 : bf_assert(chain && name);
29 18 : bf_assert(policy < _BF_TERMINAL_VERDICT_MAX);
30 :
31 16 : _chain = malloc(sizeof(*_chain));
32 16 : if (!_chain)
33 : return -ENOMEM;
34 :
35 16 : _chain->name = strdup(name);
36 16 : if (!_chain->name)
37 : return -ENOMEM;
38 :
39 16 : _chain->hook = hook;
40 16 : _chain->policy = policy;
41 :
42 16 : _chain->sets = bf_list_default(bf_set_free, bf_set_marsh);
43 16 : if (sets)
44 1 : _chain->sets = bf_list_move(*sets);
45 :
46 16 : _chain->rules = bf_list_default(bf_rule_free, bf_rule_marsh);
47 16 : if (rules)
48 2 : _chain->rules = bf_list_move(*rules);
49 42 : bf_list_foreach (&_chain->rules, rule_node)
50 6 : ((struct bf_rule *)bf_list_node_get_data(rule_node))->index = ridx++;
51 :
52 16 : *chain = TAKE_PTR(_chain);
53 :
54 16 : return 0;
55 : }
56 :
57 2 : int bf_chain_new_from_marsh(struct bf_chain **chain,
58 : const struct bf_marsh *marsh)
59 : {
60 2 : _free_bf_chain_ struct bf_chain *_chain = NULL;
61 : struct bf_marsh *child = NULL;
62 : struct bf_marsh *list_elem;
63 : enum bf_hook hook;
64 : enum bf_verdict policy;
65 : _cleanup_free_ const char *name = NULL;
66 : int r;
67 :
68 2 : bf_assert(chain && marsh);
69 :
70 2 : if (!(child = bf_marsh_next_child(marsh, child)))
71 : return -EINVAL;
72 2 : if (child->data_len == 0)
73 0 : return bf_err_r(-EINVAL, "serialized bf_chain.name is empty");
74 2 : name = strdup(child->data);
75 2 : if (!name)
76 : return -ENOMEM;
77 :
78 2 : if (!(child = bf_marsh_next_child(marsh, child)))
79 : return -EINVAL;
80 2 : memcpy(&hook, child->data, sizeof(hook));
81 :
82 2 : if (!(child = bf_marsh_next_child(marsh, child)))
83 : return -EINVAL;
84 2 : memcpy(&policy, child->data, sizeof(policy));
85 :
86 2 : r = bf_chain_new(&_chain, name, hook, policy, NULL, NULL);
87 2 : if (r)
88 : return r;
89 :
90 : // Unmarsh bf_chain.sets
91 : list_elem = NULL;
92 2 : if (!(child = bf_marsh_next_child(marsh, child)))
93 : return -EINVAL;
94 2 : while ((list_elem = bf_marsh_next_child(child, list_elem))) {
95 0 : _free_bf_set_ struct bf_set *set = NULL;
96 :
97 0 : r = bf_set_new_from_marsh(&set, list_elem);
98 0 : if (r)
99 : return r;
100 :
101 0 : r = bf_list_add_tail(&_chain->sets, set);
102 0 : if (r)
103 : return r;
104 :
105 0 : TAKE_PTR(set);
106 : }
107 :
108 : // Unmarsh bf_chain.rules
109 : list_elem = NULL;
110 2 : if (!(child = bf_marsh_next_child(marsh, child)))
111 : return -EINVAL;
112 6 : while ((list_elem = bf_marsh_next_child(child, list_elem))) {
113 0 : _free_bf_rule_ struct bf_rule *rule = NULL;
114 :
115 4 : r = bf_rule_unmarsh(list_elem, &rule);
116 4 : if (r)
117 : return r;
118 :
119 4 : r = bf_chain_add_rule(_chain, rule);
120 4 : if (r)
121 : return r;
122 :
123 4 : TAKE_PTR(rule);
124 : }
125 :
126 2 : *chain = TAKE_PTR(_chain);
127 :
128 2 : return 0;
129 : }
130 :
131 40 : void bf_chain_free(struct bf_chain **chain)
132 : {
133 40 : bf_assert(chain);
134 :
135 39 : if (!*chain)
136 : return;
137 :
138 16 : bf_list_clean(&(*chain)->sets);
139 16 : bf_list_clean(&(*chain)->rules);
140 16 : freep((void *)&(*chain)->name);
141 : freep((void *)chain);
142 : }
143 :
144 2 : int bf_chain_marsh(const struct bf_chain *chain, struct bf_marsh **marsh)
145 : {
146 2 : _free_bf_marsh_ struct bf_marsh *_marsh = NULL;
147 : int r;
148 :
149 2 : bf_assert(chain && marsh);
150 :
151 2 : r = bf_marsh_new(&_marsh, NULL, 0);
152 2 : if (r)
153 : return r;
154 :
155 2 : r = bf_marsh_add_child_raw(&_marsh, chain->name, strlen(chain->name) + 1);
156 2 : if (r < 0)
157 : return r;
158 :
159 2 : r = bf_marsh_add_child_raw(&_marsh, &chain->hook, sizeof(chain->hook));
160 2 : if (r < 0)
161 : return r;
162 :
163 2 : r = bf_marsh_add_child_raw(&_marsh, &chain->policy, sizeof(chain->policy));
164 2 : if (r)
165 : return r;
166 :
167 : {
168 : // Serialize bf_chain.sets
169 2 : _free_bf_marsh_ struct bf_marsh *child = NULL;
170 :
171 2 : r = bf_list_marsh(&chain->sets, &child);
172 2 : if (r < 0)
173 : return r;
174 :
175 2 : r = bf_marsh_add_child_obj(&_marsh, child);
176 2 : if (r < 0)
177 : return r;
178 : }
179 :
180 : {
181 : // Serialize bf_chain.rules
182 2 : _free_bf_marsh_ struct bf_marsh *child = NULL;
183 :
184 2 : r = bf_list_marsh(&chain->rules, &child);
185 2 : if (r < 0)
186 : return r;
187 :
188 2 : r = bf_marsh_add_child_obj(&_marsh, child);
189 2 : if (r < 0)
190 : return r;
191 : }
192 :
193 2 : *marsh = TAKE_PTR(_marsh);
194 :
195 2 : return 0;
196 : }
197 :
198 0 : void bf_chain_dump(const struct bf_chain *chain, prefix_t *prefix)
199 : {
200 0 : bf_assert(chain && prefix);
201 :
202 0 : DUMP(prefix, "struct bf_chain at %p", chain);
203 0 : bf_dump_prefix_push(prefix);
204 :
205 0 : DUMP(prefix, "name: %s", chain->name);
206 0 : DUMP(prefix, "hook: %s", bf_hook_to_str(chain->hook));
207 0 : DUMP(prefix, "policy: %s", bf_verdict_to_str(chain->policy));
208 :
209 0 : DUMP(prefix, "sets: bf_list<bf_set>[%lu]", bf_list_size(&chain->sets));
210 0 : bf_dump_prefix_push(prefix);
211 0 : bf_list_foreach (&chain->sets, set_node) {
212 0 : if (bf_list_is_tail(&chain->sets, set_node))
213 0 : bf_dump_prefix_last(prefix);
214 :
215 0 : bf_set_dump(bf_list_node_get_data(set_node), prefix);
216 : }
217 0 : bf_dump_prefix_pop(prefix);
218 :
219 0 : DUMP(bf_dump_prefix_last(prefix), "rules: bf_list<bf_rule>[%lu]",
220 : bf_list_size(&chain->rules));
221 0 : bf_dump_prefix_push(prefix);
222 0 : bf_list_foreach (&chain->rules, rule_node) {
223 0 : if (bf_list_is_tail(&chain->rules, rule_node))
224 0 : bf_dump_prefix_last(prefix);
225 :
226 0 : bf_rule_dump(bf_list_node_get_data(rule_node), prefix);
227 : }
228 0 : bf_dump_prefix_pop(prefix);
229 :
230 0 : bf_dump_prefix_pop(prefix);
231 0 : }
232 :
233 4 : int bf_chain_add_rule(struct bf_chain *chain, struct bf_rule *rule)
234 : {
235 4 : bf_assert(chain && rule);
236 :
237 4 : rule->index = bf_list_size(&chain->rules);
238 :
239 4 : return bf_list_add_tail(&chain->rules, rule);
240 : }
|