Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/netlabel/netlabel_cipso_v4.c
15109 views
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 <[email protected]>
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 <asm/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
static int netlbl_cipsov4_add_common(struct genl_info *info,
102
struct cipso_v4_doi *doi_def)
103
{
104
struct nlattr *nla;
105
int nla_rem;
106
u32 iter = 0;
107
108
doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
109
110
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
nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
116
if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
117
if (iter >= CIPSO_V4_TAG_MAXCNT)
118
return -EINVAL;
119
doi_def->tags[iter++] = nla_get_u8(nla);
120
}
121
while (iter < CIPSO_V4_TAG_MAXCNT)
122
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
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
struct nlattr *nla_a;
148
struct nlattr *nla_b;
149
int nla_a_rem;
150
int nla_b_rem;
151
u32 iter;
152
153
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
154
!info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
155
return -EINVAL;
156
157
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
if (doi_def == NULL)
164
return -ENOMEM;
165
doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
166
if (doi_def->map.std == NULL) {
167
ret_val = -ENOMEM;
168
goto add_std_failure;
169
}
170
doi_def->type = CIPSO_V4_MAP_TRANS;
171
172
ret_val = netlbl_cipsov4_add_common(info, doi_def);
173
if (ret_val != 0)
174
goto add_std_failure;
175
ret_val = -EINVAL;
176
177
nla_for_each_nested(nla_a,
178
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
179
nla_a_rem)
180
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
181
if (nla_validate_nested(nla_a,
182
NLBL_CIPSOV4_A_MAX,
183
netlbl_cipsov4_genl_policy) != 0)
184
goto add_std_failure;
185
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
186
switch (nla_type(nla_b)) {
187
case NLBL_CIPSOV4_A_MLSLVLLOC:
188
if (nla_get_u32(nla_b) >
189
CIPSO_V4_MAX_LOC_LVLS)
190
goto add_std_failure;
191
if (nla_get_u32(nla_b) >=
192
doi_def->map.std->lvl.local_size)
193
doi_def->map.std->lvl.local_size =
194
nla_get_u32(nla_b) + 1;
195
break;
196
case NLBL_CIPSOV4_A_MLSLVLREM:
197
if (nla_get_u32(nla_b) >
198
CIPSO_V4_MAX_REM_LVLS)
199
goto add_std_failure;
200
if (nla_get_u32(nla_b) >=
201
doi_def->map.std->lvl.cipso_size)
202
doi_def->map.std->lvl.cipso_size =
203
nla_get_u32(nla_b) + 1;
204
break;
205
}
206
}
207
doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
208
sizeof(u32),
209
GFP_KERNEL);
210
if (doi_def->map.std->lvl.local == NULL) {
211
ret_val = -ENOMEM;
212
goto add_std_failure;
213
}
214
doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
215
sizeof(u32),
216
GFP_KERNEL);
217
if (doi_def->map.std->lvl.cipso == NULL) {
218
ret_val = -ENOMEM;
219
goto add_std_failure;
220
}
221
for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
222
doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
223
for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
224
doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
225
nla_for_each_nested(nla_a,
226
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
227
nla_a_rem)
228
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
if (lvl_loc == NULL || lvl_rem == NULL)
237
goto add_std_failure;
238
doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
239
nla_get_u32(lvl_rem);
240
doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
241
nla_get_u32(lvl_loc);
242
}
243
244
if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
245
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
nla_for_each_nested(nla_a,
251
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
252
nla_a_rem)
253
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
254
if (nla_validate_nested(nla_a,
255
NLBL_CIPSOV4_A_MAX,
256
netlbl_cipsov4_genl_policy) != 0)
257
goto add_std_failure;
258
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
259
switch (nla_type(nla_b)) {
260
case NLBL_CIPSOV4_A_MLSCATLOC:
261
if (nla_get_u32(nla_b) >
262
CIPSO_V4_MAX_LOC_CATS)
263
goto add_std_failure;
264
if (nla_get_u32(nla_b) >=
265
doi_def->map.std->cat.local_size)
266
doi_def->map.std->cat.local_size =
267
nla_get_u32(nla_b) + 1;
268
break;
269
case NLBL_CIPSOV4_A_MLSCATREM:
270
if (nla_get_u32(nla_b) >
271
CIPSO_V4_MAX_REM_CATS)
272
goto add_std_failure;
273
if (nla_get_u32(nla_b) >=
274
doi_def->map.std->cat.cipso_size)
275
doi_def->map.std->cat.cipso_size =
276
nla_get_u32(nla_b) + 1;
277
break;
278
}
279
}
280
doi_def->map.std->cat.local = kcalloc(
281
doi_def->map.std->cat.local_size,
282
sizeof(u32),
283
GFP_KERNEL);
284
if (doi_def->map.std->cat.local == NULL) {
285
ret_val = -ENOMEM;
286
goto add_std_failure;
287
}
288
doi_def->map.std->cat.cipso = kcalloc(
289
doi_def->map.std->cat.cipso_size,
290
sizeof(u32),
291
GFP_KERNEL);
292
if (doi_def->map.std->cat.cipso == NULL) {
293
ret_val = -ENOMEM;
294
goto add_std_failure;
295
}
296
for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
297
doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
298
for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
299
doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
300
nla_for_each_nested(nla_a,
301
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
302
nla_a_rem)
303
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
if (cat_loc == NULL || cat_rem == NULL)
312
goto add_std_failure;
313
doi_def->map.std->cat.local[
314
nla_get_u32(cat_loc)] =
315
nla_get_u32(cat_rem);
316
doi_def->map.std->cat.cipso[
317
nla_get_u32(cat_rem)] =
318
nla_get_u32(cat_loc);
319
}
320
}
321
322
ret_val = cipso_v4_doi_add(doi_def, audit_info);
323
if (ret_val != 0)
324
goto add_std_failure;
325
return 0;
326
327
add_std_failure:
328
if (doi_def)
329
cipso_v4_doi_free(doi_def);
330
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
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
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
351
return -EINVAL;
352
353
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
354
if (doi_def == NULL)
355
return -ENOMEM;
356
doi_def->type = CIPSO_V4_MAP_PASS;
357
358
ret_val = netlbl_cipsov4_add_common(info, doi_def);
359
if (ret_val != 0)
360
goto add_pass_failure;
361
362
ret_val = cipso_v4_doi_add(doi_def, audit_info);
363
if (ret_val != 0)
364
goto add_pass_failure;
365
return 0;
366
367
add_pass_failure:
368
cipso_v4_doi_free(doi_def);
369
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
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
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
390
return -EINVAL;
391
392
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
393
if (doi_def == NULL)
394
return -ENOMEM;
395
doi_def->type = CIPSO_V4_MAP_LOCAL;
396
397
ret_val = netlbl_cipsov4_add_common(info, doi_def);
398
if (ret_val != 0)
399
goto add_local_failure;
400
401
ret_val = cipso_v4_doi_add(doi_def, audit_info);
402
if (ret_val != 0)
403
goto add_local_failure;
404
return 0;
405
406
add_local_failure:
407
cipso_v4_doi_free(doi_def);
408
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
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
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
428
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
429
return -EINVAL;
430
431
netlbl_netlink_auditinfo(skb, &audit_info);
432
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
433
case CIPSO_V4_MAP_TRANS:
434
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
435
break;
436
case CIPSO_V4_MAP_PASS:
437
ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
438
break;
439
case CIPSO_V4_MAP_LOCAL:
440
ret_val = netlbl_cipsov4_add_local(info, &audit_info);
441
break;
442
}
443
if (ret_val == 0)
444
atomic_inc(&netlabel_mgmt_protocount);
445
446
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
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
if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
479
ret_val = -EINVAL;
480
goto list_failure;
481
}
482
483
list_start:
484
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
485
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
if (data == NULL) {
492
ret_val = -ENOMEM;
493
goto list_failure;
494
}
495
496
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
497
498
rcu_read_lock();
499
doi_def = cipso_v4_doi_getdef(doi);
500
if (doi_def == NULL) {
501
ret_val = -EINVAL;
502
goto list_failure_lock;
503
}
504
505
ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
506
if (ret_val != 0)
507
goto list_failure_lock;
508
509
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
510
if (nla_a == NULL) {
511
ret_val = -ENOMEM;
512
goto list_failure_lock;
513
}
514
for (iter = 0;
515
iter < CIPSO_V4_TAG_MAXCNT &&
516
doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
517
iter++) {
518
ret_val = nla_put_u8(ans_skb,
519
NLBL_CIPSOV4_A_TAG,
520
doi_def->tags[iter]);
521
if (ret_val != 0)
522
goto list_failure_lock;
523
}
524
nla_nest_end(ans_skb, nla_a);
525
526
switch (doi_def->type) {
527
case CIPSO_V4_MAP_TRANS:
528
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
529
if (nla_a == NULL) {
530
ret_val = -ENOMEM;
531
goto list_failure_lock;
532
}
533
for (iter = 0;
534
iter < doi_def->map.std->lvl.local_size;
535
iter++) {
536
if (doi_def->map.std->lvl.local[iter] ==
537
CIPSO_V4_INV_LVL)
538
continue;
539
540
nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
541
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
if (ret_val != 0)
549
goto list_retry;
550
ret_val = nla_put_u32(ans_skb,
551
NLBL_CIPSOV4_A_MLSLVLREM,
552
doi_def->map.std->lvl.local[iter]);
553
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
if (nla_a == NULL) {
561
ret_val = -ENOMEM;
562
goto list_retry;
563
}
564
for (iter = 0;
565
iter < doi_def->map.std->cat.local_size;
566
iter++) {
567
if (doi_def->map.std->cat.local[iter] ==
568
CIPSO_V4_INV_CAT)
569
continue;
570
571
nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
572
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
if (ret_val != 0)
580
goto list_retry;
581
ret_val = nla_put_u32(ans_skb,
582
NLBL_CIPSOV4_A_MLSCATREM,
583
doi_def->map.std->cat.local[iter]);
584
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
return genlmsg_reply(ans_skb, info);
596
597
list_retry:
598
/* XXX - this limit is a guesstimate */
599
if (nlsze_mult < 4) {
600
rcu_read_unlock();
601
kfree_skb(ans_skb);
602
nlsze_mult *= 2;
603
goto list_start;
604
}
605
list_failure_lock:
606
rcu_read_unlock();
607
list_failure:
608
kfree_skb(ans_skb);
609
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
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
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
631
cb_arg->seq, &netlbl_cipsov4_gnl_family,
632
NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
633
if (data == NULL)
634
goto listall_cb_failure;
635
636
ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
637
if (ret_val != 0)
638
goto listall_cb_failure;
639
ret_val = nla_put_u32(cb_arg->skb,
640
NLBL_CIPSOV4_A_MTYPE,
641
doi_def->type);
642
if (ret_val != 0)
643
goto listall_cb_failure;
644
645
return genlmsg_end(cb_arg->skb, data);
646
647
listall_cb_failure:
648
genlmsg_cancel(cb_arg->skb, data);
649
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
static int netlbl_cipsov4_listall(struct sk_buff *skb,
663
struct netlink_callback *cb)
664
{
665
struct netlbl_cipsov4_doiwalk_arg cb_arg;
666
u32 doi_skip = cb->args[0];
667
668
cb_arg.nl_cb = cb;
669
cb_arg.skb = skb;
670
cb_arg.seq = cb->nlh->nlmsg_seq;
671
672
cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
673
674
cb->args[0] = doi_skip;
675
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
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
if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
695
entry->type_def.cipsov4->doi == cb_arg->doi)
696
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
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
u32 skip_bkt = 0;
717
u32 skip_chain = 0;
718
719
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
720
return -EINVAL;
721
722
netlbl_netlink_auditinfo(skb, &audit_info);
723
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
724
cb_arg.audit_info = &audit_info;
725
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
726
netlbl_cipsov4_remove_cb, &cb_arg);
727
if (ret_val == 0 || ret_val == -ENOENT) {
728
ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
729
if (ret_val == 0)
730
atomic_dec(&netlabel_mgmt_protocount);
731
}
732
733
return ret_val;
734
}
735
736
/*
737
* NetLabel Generic NETLINK Command Definitions
738
*/
739
740
static 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
int __init netlbl_cipsov4_genl_init(void)
784
{
785
return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family,
786
netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops));
787
}
788
789