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