Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * NetLabel CIPSO/IPv4 Support
4 : : *
5 : : * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
6 : : * NetLabel system manages static and dynamic label mappings for network
7 : : * protocols such as CIPSO and RIPSO.
8 : : *
9 : : * Author: Paul Moore <paul@paul-moore.com>
10 : : */
11 : :
12 : : /*
13 : : * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14 : : */
15 : :
16 : : #include <linux/types.h>
17 : : #include <linux/socket.h>
18 : : #include <linux/string.h>
19 : : #include <linux/skbuff.h>
20 : : #include <linux/audit.h>
21 : : #include <linux/slab.h>
22 : : #include <net/sock.h>
23 : : #include <net/netlink.h>
24 : : #include <net/genetlink.h>
25 : : #include <net/netlabel.h>
26 : : #include <net/cipso_ipv4.h>
27 : : #include <linux/atomic.h>
28 : :
29 : : #include "netlabel_user.h"
30 : : #include "netlabel_cipso_v4.h"
31 : : #include "netlabel_mgmt.h"
32 : : #include "netlabel_domainhash.h"
33 : :
34 : : /* Argument struct for cipso_v4_doi_walk() */
35 : : struct netlbl_cipsov4_doiwalk_arg {
36 : : struct netlink_callback *nl_cb;
37 : : struct sk_buff *skb;
38 : : u32 seq;
39 : : };
40 : :
41 : : /* Argument struct for netlbl_domhsh_walk() */
42 : : struct netlbl_domhsh_walk_arg {
43 : : struct netlbl_audit *audit_info;
44 : : u32 doi;
45 : : };
46 : :
47 : : /* NetLabel Generic NETLINK CIPSOv4 family */
48 : : static struct genl_family netlbl_cipsov4_gnl_family;
49 : : /* NetLabel Netlink attribute policy */
50 : : static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
51 : : [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
52 : : [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
53 : : [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
54 : : [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
55 : : [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
56 : : [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
57 : : [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
58 : : [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
59 : : [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
60 : : [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
61 : : [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
62 : : [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
63 : : };
64 : :
65 : : /*
66 : : * Helper Functions
67 : : */
68 : :
69 : : /**
70 : : * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
71 : : * @info: the Generic NETLINK info block
72 : : * @doi_def: the CIPSO V4 DOI definition
73 : : *
74 : : * Description:
75 : : * Parse the common sections of a ADD message and fill in the related values
76 : : * in @doi_def. Returns zero on success, negative values on failure.
77 : : *
78 : : */
79 : : static int netlbl_cipsov4_add_common(struct genl_info *info,
80 : : struct cipso_v4_doi *doi_def)
81 : : {
82 : : struct nlattr *nla;
83 : : int nla_rem;
84 : : u32 iter = 0;
85 : :
86 : : doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
87 : :
88 : : if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_TAGLST],
89 : : NLBL_CIPSOV4_A_MAX,
90 : : netlbl_cipsov4_genl_policy,
91 : : NULL) != 0)
92 : : return -EINVAL;
93 : :
94 : : nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
95 : : if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
96 : : if (iter >= CIPSO_V4_TAG_MAXCNT)
97 : : return -EINVAL;
98 : : doi_def->tags[iter++] = nla_get_u8(nla);
99 : : }
100 : : while (iter < CIPSO_V4_TAG_MAXCNT)
101 : : doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
102 : :
103 : : return 0;
104 : : }
105 : :
106 : : /*
107 : : * NetLabel Command Handlers
108 : : */
109 : :
110 : : /**
111 : : * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
112 : : * @info: the Generic NETLINK info block
113 : : * @audit_info: NetLabel audit information
114 : : *
115 : : * Description:
116 : : * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
117 : : * message and add it to the CIPSO V4 engine. Return zero on success and
118 : : * non-zero on error.
119 : : *
120 : : */
121 : 0 : static int netlbl_cipsov4_add_std(struct genl_info *info,
122 : : struct netlbl_audit *audit_info)
123 : : {
124 : 0 : int ret_val = -EINVAL;
125 : 0 : struct cipso_v4_doi *doi_def = NULL;
126 : 0 : struct nlattr *nla_a;
127 : 0 : struct nlattr *nla_b;
128 : 0 : int nla_a_rem;
129 : 0 : int nla_b_rem;
130 : 0 : u32 iter;
131 : :
132 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
133 [ # # ]: 0 : !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
134 : : return -EINVAL;
135 : :
136 [ # # ]: 0 : if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
137 : : NLBL_CIPSOV4_A_MAX,
138 : : netlbl_cipsov4_genl_policy,
139 : : NULL) != 0)
140 : : return -EINVAL;
141 : :
142 : 0 : doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
143 [ # # ]: 0 : if (doi_def == NULL)
144 : : return -ENOMEM;
145 : 0 : doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
146 [ # # ]: 0 : if (doi_def->map.std == NULL) {
147 : 0 : ret_val = -ENOMEM;
148 : 0 : goto add_std_failure;
149 : : }
150 : 0 : doi_def->type = CIPSO_V4_MAP_TRANS;
151 : :
152 : 0 : ret_val = netlbl_cipsov4_add_common(info, doi_def);
153 [ # # ]: 0 : if (ret_val != 0)
154 : 0 : goto add_std_failure;
155 : 0 : ret_val = -EINVAL;
156 : :
157 [ # # ]: 0 : nla_for_each_nested(nla_a,
158 : : info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
159 : : nla_a_rem)
160 [ # # ]: 0 : if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
161 [ # # ]: 0 : if (nla_validate_nested_deprecated(nla_a,
162 : : NLBL_CIPSOV4_A_MAX,
163 : : netlbl_cipsov4_genl_policy,
164 : : NULL) != 0)
165 : 0 : goto add_std_failure;
166 [ # # ]: 0 : nla_for_each_nested(nla_b, nla_a, nla_b_rem)
167 [ # # # ]: 0 : switch (nla_type(nla_b)) {
168 : : case NLBL_CIPSOV4_A_MLSLVLLOC:
169 [ # # ]: 0 : if (nla_get_u32(nla_b) >
170 : : CIPSO_V4_MAX_LOC_LVLS)
171 : 0 : goto add_std_failure;
172 [ # # ]: 0 : if (nla_get_u32(nla_b) >=
173 [ # # ]: 0 : doi_def->map.std->lvl.local_size)
174 : 0 : doi_def->map.std->lvl.local_size =
175 : 0 : nla_get_u32(nla_b) + 1;
176 : : break;
177 : : case NLBL_CIPSOV4_A_MLSLVLREM:
178 [ # # ]: 0 : if (nla_get_u32(nla_b) >
179 : : CIPSO_V4_MAX_REM_LVLS)
180 : 0 : goto add_std_failure;
181 [ # # ]: 0 : if (nla_get_u32(nla_b) >=
182 [ # # ]: 0 : doi_def->map.std->lvl.cipso_size)
183 : 0 : doi_def->map.std->lvl.cipso_size =
184 : 0 : nla_get_u32(nla_b) + 1;
185 : : break;
186 : : }
187 : 0 : }
188 : 0 : doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
189 : : sizeof(u32),
190 : : GFP_KERNEL);
191 [ # # ]: 0 : if (doi_def->map.std->lvl.local == NULL) {
192 : 0 : ret_val = -ENOMEM;
193 : 0 : goto add_std_failure;
194 : : }
195 : 0 : doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
196 : : sizeof(u32),
197 : : GFP_KERNEL);
198 [ # # ]: 0 : if (doi_def->map.std->lvl.cipso == NULL) {
199 : 0 : ret_val = -ENOMEM;
200 : 0 : goto add_std_failure;
201 : : }
202 [ # # ]: 0 : for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
203 : 0 : doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
204 [ # # ]: 0 : for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
205 : 0 : doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
206 [ # # ]: 0 : nla_for_each_nested(nla_a,
207 : : info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
208 : : nla_a_rem)
209 [ # # ]: 0 : if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
210 : 0 : struct nlattr *lvl_loc;
211 : 0 : struct nlattr *lvl_rem;
212 : :
213 : 0 : lvl_loc = nla_find_nested(nla_a,
214 : : NLBL_CIPSOV4_A_MLSLVLLOC);
215 : 0 : lvl_rem = nla_find_nested(nla_a,
216 : : NLBL_CIPSOV4_A_MLSLVLREM);
217 [ # # ]: 0 : if (lvl_loc == NULL || lvl_rem == NULL)
218 : 0 : goto add_std_failure;
219 : 0 : doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
220 : : nla_get_u32(lvl_rem);
221 : 0 : doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
222 : : nla_get_u32(lvl_loc);
223 : : }
224 : :
225 [ # # ]: 0 : if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
226 [ # # ]: 0 : if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
227 : : NLBL_CIPSOV4_A_MAX,
228 : : netlbl_cipsov4_genl_policy,
229 : : NULL) != 0)
230 : 0 : goto add_std_failure;
231 : :
232 [ # # ]: 0 : nla_for_each_nested(nla_a,
233 : : info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
234 : : nla_a_rem)
235 [ # # ]: 0 : if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
236 [ # # ]: 0 : if (nla_validate_nested_deprecated(nla_a,
237 : : NLBL_CIPSOV4_A_MAX,
238 : : netlbl_cipsov4_genl_policy,
239 : : NULL) != 0)
240 : 0 : goto add_std_failure;
241 [ # # ]: 0 : nla_for_each_nested(nla_b, nla_a, nla_b_rem)
242 [ # # # ]: 0 : switch (nla_type(nla_b)) {
243 : : case NLBL_CIPSOV4_A_MLSCATLOC:
244 [ # # ]: 0 : if (nla_get_u32(nla_b) >
245 : : CIPSO_V4_MAX_LOC_CATS)
246 : 0 : goto add_std_failure;
247 [ # # ]: 0 : if (nla_get_u32(nla_b) >=
248 [ # # ]: 0 : doi_def->map.std->cat.local_size)
249 : 0 : doi_def->map.std->cat.local_size =
250 : 0 : nla_get_u32(nla_b) + 1;
251 : : break;
252 : : case NLBL_CIPSOV4_A_MLSCATREM:
253 [ # # ]: 0 : if (nla_get_u32(nla_b) >
254 : : CIPSO_V4_MAX_REM_CATS)
255 : 0 : goto add_std_failure;
256 [ # # ]: 0 : if (nla_get_u32(nla_b) >=
257 [ # # ]: 0 : doi_def->map.std->cat.cipso_size)
258 : 0 : doi_def->map.std->cat.cipso_size =
259 : 0 : nla_get_u32(nla_b) + 1;
260 : : break;
261 : : }
262 : 0 : }
263 : 0 : doi_def->map.std->cat.local = kcalloc(
264 : 0 : doi_def->map.std->cat.local_size,
265 : : sizeof(u32),
266 : : GFP_KERNEL);
267 [ # # ]: 0 : if (doi_def->map.std->cat.local == NULL) {
268 : 0 : ret_val = -ENOMEM;
269 : 0 : goto add_std_failure;
270 : : }
271 : 0 : doi_def->map.std->cat.cipso = kcalloc(
272 : 0 : doi_def->map.std->cat.cipso_size,
273 : : sizeof(u32),
274 : : GFP_KERNEL);
275 [ # # ]: 0 : if (doi_def->map.std->cat.cipso == NULL) {
276 : 0 : ret_val = -ENOMEM;
277 : 0 : goto add_std_failure;
278 : : }
279 [ # # ]: 0 : for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
280 : 0 : doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
281 [ # # ]: 0 : for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
282 : 0 : doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
283 [ # # ]: 0 : nla_for_each_nested(nla_a,
284 : : info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
285 : : nla_a_rem)
286 [ # # ]: 0 : if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
287 : 0 : struct nlattr *cat_loc;
288 : 0 : struct nlattr *cat_rem;
289 : :
290 : 0 : cat_loc = nla_find_nested(nla_a,
291 : : NLBL_CIPSOV4_A_MLSCATLOC);
292 : 0 : cat_rem = nla_find_nested(nla_a,
293 : : NLBL_CIPSOV4_A_MLSCATREM);
294 [ # # ]: 0 : if (cat_loc == NULL || cat_rem == NULL)
295 : 0 : goto add_std_failure;
296 : 0 : doi_def->map.std->cat.local[
297 : 0 : nla_get_u32(cat_loc)] =
298 : : nla_get_u32(cat_rem);
299 : 0 : doi_def->map.std->cat.cipso[
300 : 0 : nla_get_u32(cat_rem)] =
301 : : nla_get_u32(cat_loc);
302 : : }
303 : : }
304 : :
305 : 0 : ret_val = cipso_v4_doi_add(doi_def, audit_info);
306 [ # # ]: 0 : if (ret_val != 0)
307 : 0 : goto add_std_failure;
308 : : return 0;
309 : :
310 : 0 : add_std_failure:
311 : 0 : cipso_v4_doi_free(doi_def);
312 : 0 : return ret_val;
313 : : }
314 : :
315 : : /**
316 : : * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
317 : : * @info: the Generic NETLINK info block
318 : : * @audit_info: NetLabel audit information
319 : : *
320 : : * Description:
321 : : * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
322 : : * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
323 : : * error.
324 : : *
325 : : */
326 : 0 : static int netlbl_cipsov4_add_pass(struct genl_info *info,
327 : : struct netlbl_audit *audit_info)
328 : : {
329 : 0 : int ret_val;
330 : 0 : struct cipso_v4_doi *doi_def = NULL;
331 : :
332 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
333 : : return -EINVAL;
334 : :
335 : 0 : doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
336 [ # # ]: 0 : if (doi_def == NULL)
337 : : return -ENOMEM;
338 : 0 : doi_def->type = CIPSO_V4_MAP_PASS;
339 : :
340 : 0 : ret_val = netlbl_cipsov4_add_common(info, doi_def);
341 [ # # ]: 0 : if (ret_val != 0)
342 : 0 : goto add_pass_failure;
343 : :
344 : 0 : ret_val = cipso_v4_doi_add(doi_def, audit_info);
345 [ # # ]: 0 : if (ret_val != 0)
346 : 0 : goto add_pass_failure;
347 : : return 0;
348 : :
349 : 0 : add_pass_failure:
350 : 0 : cipso_v4_doi_free(doi_def);
351 : 0 : return ret_val;
352 : : }
353 : :
354 : : /**
355 : : * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
356 : : * @info: the Generic NETLINK info block
357 : : * @audit_info: NetLabel audit information
358 : : *
359 : : * Description:
360 : : * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
361 : : * message and add it to the CIPSO V4 engine. Return zero on success and
362 : : * non-zero on error.
363 : : *
364 : : */
365 : 0 : static int netlbl_cipsov4_add_local(struct genl_info *info,
366 : : struct netlbl_audit *audit_info)
367 : : {
368 : 0 : int ret_val;
369 : 0 : struct cipso_v4_doi *doi_def = NULL;
370 : :
371 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
372 : : return -EINVAL;
373 : :
374 : 0 : doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
375 [ # # ]: 0 : if (doi_def == NULL)
376 : : return -ENOMEM;
377 : 0 : doi_def->type = CIPSO_V4_MAP_LOCAL;
378 : :
379 : 0 : ret_val = netlbl_cipsov4_add_common(info, doi_def);
380 [ # # ]: 0 : if (ret_val != 0)
381 : 0 : goto add_local_failure;
382 : :
383 : 0 : ret_val = cipso_v4_doi_add(doi_def, audit_info);
384 [ # # ]: 0 : if (ret_val != 0)
385 : 0 : goto add_local_failure;
386 : : return 0;
387 : :
388 : 0 : add_local_failure:
389 : 0 : cipso_v4_doi_free(doi_def);
390 : 0 : return ret_val;
391 : : }
392 : :
393 : : /**
394 : : * netlbl_cipsov4_add - Handle an ADD message
395 : : * @skb: the NETLINK buffer
396 : : * @info: the Generic NETLINK info block
397 : : *
398 : : * Description:
399 : : * Create a new DOI definition based on the given ADD message and add it to the
400 : : * CIPSO V4 engine. Returns zero on success, negative values on failure.
401 : : *
402 : : */
403 : 0 : static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
404 : :
405 : : {
406 : 0 : int ret_val = -EINVAL;
407 : 0 : struct netlbl_audit audit_info;
408 : :
409 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
410 [ # # ]: 0 : !info->attrs[NLBL_CIPSOV4_A_MTYPE])
411 : : return -EINVAL;
412 : :
413 : 0 : netlbl_netlink_auditinfo(skb, &audit_info);
414 [ # # # # ]: 0 : switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
415 : 0 : case CIPSO_V4_MAP_TRANS:
416 : 0 : ret_val = netlbl_cipsov4_add_std(info, &audit_info);
417 : 0 : break;
418 : 0 : case CIPSO_V4_MAP_PASS:
419 : 0 : ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
420 : 0 : break;
421 : 0 : case CIPSO_V4_MAP_LOCAL:
422 : 0 : ret_val = netlbl_cipsov4_add_local(info, &audit_info);
423 : 0 : break;
424 : : }
425 [ # # ]: 0 : if (ret_val == 0)
426 : 0 : atomic_inc(&netlabel_mgmt_protocount);
427 : :
428 : : return ret_val;
429 : : }
430 : :
431 : : /**
432 : : * netlbl_cipsov4_list - Handle a LIST message
433 : : * @skb: the NETLINK buffer
434 : : * @info: the Generic NETLINK info block
435 : : *
436 : : * Description:
437 : : * Process a user generated LIST message and respond accordingly. While the
438 : : * response message generated by the kernel is straightforward, determining
439 : : * before hand the size of the buffer to allocate is not (we have to generate
440 : : * the message to know the size). In order to keep this function sane what we
441 : : * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
442 : : * that size, if we fail then we restart with a larger buffer and try again.
443 : : * We continue in this manner until we hit a limit of failed attempts then we
444 : : * give up and just send an error message. Returns zero on success and
445 : : * negative values on error.
446 : : *
447 : : */
448 : 0 : static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
449 : : {
450 : 0 : int ret_val;
451 : 0 : struct sk_buff *ans_skb = NULL;
452 : 0 : u32 nlsze_mult = 1;
453 : 0 : void *data;
454 : 0 : u32 doi;
455 : 0 : struct nlattr *nla_a;
456 : 0 : struct nlattr *nla_b;
457 : 0 : struct cipso_v4_doi *doi_def;
458 : 0 : u32 iter;
459 : :
460 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
461 : 0 : ret_val = -EINVAL;
462 : 0 : goto list_failure;
463 : : }
464 : :
465 : 0 : list_start:
466 : 0 : ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
467 [ # # ]: 0 : if (ans_skb == NULL) {
468 : 0 : ret_val = -ENOMEM;
469 : 0 : goto list_failure;
470 : : }
471 : 0 : data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
472 : : 0, NLBL_CIPSOV4_C_LIST);
473 [ # # ]: 0 : if (data == NULL) {
474 : 0 : ret_val = -ENOMEM;
475 : 0 : goto list_failure;
476 : : }
477 : :
478 : 0 : doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
479 : :
480 : 0 : rcu_read_lock();
481 : 0 : doi_def = cipso_v4_doi_getdef(doi);
482 [ # # ]: 0 : if (doi_def == NULL) {
483 : 0 : ret_val = -EINVAL;
484 : 0 : goto list_failure_lock;
485 : : }
486 : :
487 : 0 : ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
488 [ # # ]: 0 : if (ret_val != 0)
489 : 0 : goto list_failure_lock;
490 : :
491 : 0 : nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
492 [ # # ]: 0 : if (nla_a == NULL) {
493 : 0 : ret_val = -ENOMEM;
494 : 0 : goto list_failure_lock;
495 : : }
496 : 0 : for (iter = 0;
497 [ # # ]: 0 : iter < CIPSO_V4_TAG_MAXCNT &&
498 [ # # ]: 0 : doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
499 : 0 : iter++) {
500 : 0 : ret_val = nla_put_u8(ans_skb,
501 : : NLBL_CIPSOV4_A_TAG,
502 : : doi_def->tags[iter]);
503 [ # # ]: 0 : if (ret_val != 0)
504 : 0 : goto list_failure_lock;
505 : : }
506 [ # # ]: 0 : nla_nest_end(ans_skb, nla_a);
507 : :
508 [ # # ]: 0 : switch (doi_def->type) {
509 : : case CIPSO_V4_MAP_TRANS:
510 : 0 : nla_a = nla_nest_start_noflag(ans_skb,
511 : : NLBL_CIPSOV4_A_MLSLVLLST);
512 [ # # ]: 0 : if (nla_a == NULL) {
513 : 0 : ret_val = -ENOMEM;
514 : 0 : goto list_failure_lock;
515 : : }
516 : 0 : for (iter = 0;
517 [ # # ]: 0 : iter < doi_def->map.std->lvl.local_size;
518 : 0 : iter++) {
519 [ # # ]: 0 : if (doi_def->map.std->lvl.local[iter] ==
520 : : CIPSO_V4_INV_LVL)
521 : 0 : continue;
522 : :
523 : 0 : nla_b = nla_nest_start_noflag(ans_skb,
524 : : NLBL_CIPSOV4_A_MLSLVL);
525 [ # # ]: 0 : if (nla_b == NULL) {
526 : 0 : ret_val = -ENOMEM;
527 : 0 : goto list_retry;
528 : : }
529 : 0 : ret_val = nla_put_u32(ans_skb,
530 : : NLBL_CIPSOV4_A_MLSLVLLOC,
531 : : iter);
532 [ # # ]: 0 : if (ret_val != 0)
533 : 0 : goto list_retry;
534 : 0 : ret_val = nla_put_u32(ans_skb,
535 : : NLBL_CIPSOV4_A_MLSLVLREM,
536 : 0 : doi_def->map.std->lvl.local[iter]);
537 [ # # ]: 0 : if (ret_val != 0)
538 : 0 : goto list_retry;
539 : 0 : nla_nest_end(ans_skb, nla_b);
540 : : }
541 : 0 : nla_nest_end(ans_skb, nla_a);
542 : :
543 : 0 : nla_a = nla_nest_start_noflag(ans_skb,
544 : : NLBL_CIPSOV4_A_MLSCATLST);
545 [ # # ]: 0 : if (nla_a == NULL) {
546 : 0 : ret_val = -ENOMEM;
547 : 0 : goto list_retry;
548 : : }
549 : 0 : for (iter = 0;
550 [ # # ]: 0 : iter < doi_def->map.std->cat.local_size;
551 : 0 : iter++) {
552 [ # # ]: 0 : if (doi_def->map.std->cat.local[iter] ==
553 : : CIPSO_V4_INV_CAT)
554 : 0 : continue;
555 : :
556 : 0 : nla_b = nla_nest_start_noflag(ans_skb,
557 : : NLBL_CIPSOV4_A_MLSCAT);
558 [ # # ]: 0 : if (nla_b == NULL) {
559 : 0 : ret_val = -ENOMEM;
560 : 0 : goto list_retry;
561 : : }
562 : 0 : ret_val = nla_put_u32(ans_skb,
563 : : NLBL_CIPSOV4_A_MLSCATLOC,
564 : : iter);
565 [ # # ]: 0 : if (ret_val != 0)
566 : 0 : goto list_retry;
567 : 0 : ret_val = nla_put_u32(ans_skb,
568 : : NLBL_CIPSOV4_A_MLSCATREM,
569 : 0 : doi_def->map.std->cat.local[iter]);
570 [ # # ]: 0 : if (ret_val != 0)
571 : 0 : goto list_retry;
572 : 0 : nla_nest_end(ans_skb, nla_b);
573 : : }
574 : 0 : nla_nest_end(ans_skb, nla_a);
575 : :
576 : : break;
577 : : }
578 : 0 : rcu_read_unlock();
579 : :
580 : 0 : genlmsg_end(ans_skb, data);
581 : 0 : return genlmsg_reply(ans_skb, info);
582 : :
583 : 0 : list_retry:
584 : : /* XXX - this limit is a guesstimate */
585 [ # # ]: 0 : if (nlsze_mult < 4) {
586 : 0 : rcu_read_unlock();
587 : 0 : kfree_skb(ans_skb);
588 : 0 : nlsze_mult *= 2;
589 : 0 : goto list_start;
590 : : }
591 : 0 : list_failure_lock:
592 : 0 : rcu_read_unlock();
593 : 0 : list_failure:
594 : 0 : kfree_skb(ans_skb);
595 : 0 : return ret_val;
596 : : }
597 : :
598 : : /**
599 : : * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
600 : : * @doi_def: the CIPSOv4 DOI definition
601 : : * @arg: the netlbl_cipsov4_doiwalk_arg structure
602 : : *
603 : : * Description:
604 : : * This function is designed to be used as a callback to the
605 : : * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
606 : : * message. Returns the size of the message on success, negative values on
607 : : * failure.
608 : : *
609 : : */
610 : 0 : static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
611 : : {
612 : 0 : int ret_val = -ENOMEM;
613 : 0 : struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
614 : 0 : void *data;
615 : :
616 : 0 : data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
617 : : cb_arg->seq, &netlbl_cipsov4_gnl_family,
618 : : NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
619 [ # # ]: 0 : if (data == NULL)
620 : 0 : goto listall_cb_failure;
621 : :
622 : 0 : ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
623 [ # # ]: 0 : if (ret_val != 0)
624 : 0 : goto listall_cb_failure;
625 : 0 : ret_val = nla_put_u32(cb_arg->skb,
626 : : NLBL_CIPSOV4_A_MTYPE,
627 : : doi_def->type);
628 [ # # ]: 0 : if (ret_val != 0)
629 : 0 : goto listall_cb_failure;
630 : :
631 : 0 : genlmsg_end(cb_arg->skb, data);
632 : 0 : return 0;
633 : :
634 : 0 : listall_cb_failure:
635 [ # # ]: 0 : genlmsg_cancel(cb_arg->skb, data);
636 : : return ret_val;
637 : : }
638 : :
639 : : /**
640 : : * netlbl_cipsov4_listall - Handle a LISTALL message
641 : : * @skb: the NETLINK buffer
642 : : * @cb: the NETLINK callback
643 : : *
644 : : * Description:
645 : : * Process a user generated LISTALL message and respond accordingly. Returns
646 : : * zero on success and negative values on error.
647 : : *
648 : : */
649 : 0 : static int netlbl_cipsov4_listall(struct sk_buff *skb,
650 : : struct netlink_callback *cb)
651 : : {
652 : 0 : struct netlbl_cipsov4_doiwalk_arg cb_arg;
653 : 0 : u32 doi_skip = cb->args[0];
654 : :
655 : 0 : cb_arg.nl_cb = cb;
656 : 0 : cb_arg.skb = skb;
657 : 0 : cb_arg.seq = cb->nlh->nlmsg_seq;
658 : :
659 : 0 : cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
660 : :
661 : 0 : cb->args[0] = doi_skip;
662 : 0 : return skb->len;
663 : : }
664 : :
665 : : /**
666 : : * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
667 : : * @entry: LSM domain mapping entry
668 : : * @arg: the netlbl_domhsh_walk_arg structure
669 : : *
670 : : * Description:
671 : : * This function is intended for use by netlbl_cipsov4_remove() as the callback
672 : : * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
673 : : * which are associated with the CIPSO DOI specified in @arg. Returns zero on
674 : : * success, negative values on failure.
675 : : *
676 : : */
677 : 0 : static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
678 : : {
679 : 0 : struct netlbl_domhsh_walk_arg *cb_arg = arg;
680 : :
681 [ # # ]: 0 : if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
682 [ # # ]: 0 : entry->def.cipso->doi == cb_arg->doi)
683 : 0 : return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
684 : :
685 : : return 0;
686 : : }
687 : :
688 : : /**
689 : : * netlbl_cipsov4_remove - Handle a REMOVE message
690 : : * @skb: the NETLINK buffer
691 : : * @info: the Generic NETLINK info block
692 : : *
693 : : * Description:
694 : : * Process a user generated REMOVE message and respond accordingly. Returns
695 : : * zero on success, negative values on failure.
696 : : *
697 : : */
698 : 0 : static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
699 : : {
700 : 0 : int ret_val = -EINVAL;
701 : 0 : struct netlbl_domhsh_walk_arg cb_arg;
702 : 0 : struct netlbl_audit audit_info;
703 : 0 : u32 skip_bkt = 0;
704 : 0 : u32 skip_chain = 0;
705 : :
706 [ # # ]: 0 : if (!info->attrs[NLBL_CIPSOV4_A_DOI])
707 : : return -EINVAL;
708 : :
709 : 0 : netlbl_netlink_auditinfo(skb, &audit_info);
710 : 0 : cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
711 : 0 : cb_arg.audit_info = &audit_info;
712 : 0 : ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
713 : : netlbl_cipsov4_remove_cb, &cb_arg);
714 [ # # ]: 0 : if (ret_val == 0 || ret_val == -ENOENT) {
715 : 0 : ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
716 [ # # ]: 0 : if (ret_val == 0)
717 : 0 : atomic_dec(&netlabel_mgmt_protocount);
718 : : }
719 : :
720 : : return ret_val;
721 : : }
722 : :
723 : : /*
724 : : * NetLabel Generic NETLINK Command Definitions
725 : : */
726 : :
727 : : static const struct genl_ops netlbl_cipsov4_ops[] = {
728 : : {
729 : : .cmd = NLBL_CIPSOV4_C_ADD,
730 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
731 : : .flags = GENL_ADMIN_PERM,
732 : : .doit = netlbl_cipsov4_add,
733 : : .dumpit = NULL,
734 : : },
735 : : {
736 : : .cmd = NLBL_CIPSOV4_C_REMOVE,
737 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
738 : : .flags = GENL_ADMIN_PERM,
739 : : .doit = netlbl_cipsov4_remove,
740 : : .dumpit = NULL,
741 : : },
742 : : {
743 : : .cmd = NLBL_CIPSOV4_C_LIST,
744 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
745 : : .flags = 0,
746 : : .doit = netlbl_cipsov4_list,
747 : : .dumpit = NULL,
748 : : },
749 : : {
750 : : .cmd = NLBL_CIPSOV4_C_LISTALL,
751 : : .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
752 : : .flags = 0,
753 : : .doit = NULL,
754 : : .dumpit = netlbl_cipsov4_listall,
755 : : },
756 : : };
757 : :
758 : : static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
759 : : .hdrsize = 0,
760 : : .name = NETLBL_NLTYPE_CIPSOV4_NAME,
761 : : .version = NETLBL_PROTO_VERSION,
762 : : .maxattr = NLBL_CIPSOV4_A_MAX,
763 : : .policy = netlbl_cipsov4_genl_policy,
764 : : .module = THIS_MODULE,
765 : : .ops = netlbl_cipsov4_ops,
766 : : .n_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
767 : : };
768 : :
769 : : /*
770 : : * NetLabel Generic NETLINK Protocol Functions
771 : : */
772 : :
773 : : /**
774 : : * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
775 : : *
776 : : * Description:
777 : : * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
778 : : * mechanism. Returns zero on success, negative values on failure.
779 : : *
780 : : */
781 : 3 : int __init netlbl_cipsov4_genl_init(void)
782 : : {
783 : 3 : return genl_register_family(&netlbl_cipsov4_gnl_family);
784 : : }
|