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