Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/netlabel/netlabel_cipso_v4.c
26278 views
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 <[email protected]>
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
static int netlbl_cipsov4_add_std(struct genl_info *info,
122
struct netlbl_audit *audit_info)
123
{
124
int ret_val = -EINVAL;
125
struct cipso_v4_doi *doi_def = NULL;
126
struct nlattr *nla_a;
127
struct nlattr *nla_b;
128
int nla_a_rem;
129
int nla_b_rem;
130
u32 iter;
131
132
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
133
!info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
134
return -EINVAL;
135
136
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
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
143
if (doi_def == NULL)
144
return -ENOMEM;
145
doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
146
if (doi_def->map.std == NULL) {
147
kfree(doi_def);
148
return -ENOMEM;
149
}
150
doi_def->type = CIPSO_V4_MAP_TRANS;
151
152
ret_val = netlbl_cipsov4_add_common(info, doi_def);
153
if (ret_val != 0)
154
goto add_std_failure;
155
ret_val = -EINVAL;
156
157
nla_for_each_nested(nla_a,
158
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
159
nla_a_rem)
160
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
161
if (nla_validate_nested_deprecated(nla_a,
162
NLBL_CIPSOV4_A_MAX,
163
netlbl_cipsov4_genl_policy,
164
NULL) != 0)
165
goto add_std_failure;
166
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
167
switch (nla_type(nla_b)) {
168
case NLBL_CIPSOV4_A_MLSLVLLOC:
169
if (nla_get_u32(nla_b) >
170
CIPSO_V4_MAX_LOC_LVLS)
171
goto add_std_failure;
172
if (nla_get_u32(nla_b) >=
173
doi_def->map.std->lvl.local_size)
174
doi_def->map.std->lvl.local_size =
175
nla_get_u32(nla_b) + 1;
176
break;
177
case NLBL_CIPSOV4_A_MLSLVLREM:
178
if (nla_get_u32(nla_b) >
179
CIPSO_V4_MAX_REM_LVLS)
180
goto add_std_failure;
181
if (nla_get_u32(nla_b) >=
182
doi_def->map.std->lvl.cipso_size)
183
doi_def->map.std->lvl.cipso_size =
184
nla_get_u32(nla_b) + 1;
185
break;
186
}
187
}
188
doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
189
sizeof(u32),
190
GFP_KERNEL | __GFP_NOWARN);
191
if (doi_def->map.std->lvl.local == NULL) {
192
ret_val = -ENOMEM;
193
goto add_std_failure;
194
}
195
doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
196
sizeof(u32),
197
GFP_KERNEL | __GFP_NOWARN);
198
if (doi_def->map.std->lvl.cipso == NULL) {
199
ret_val = -ENOMEM;
200
goto add_std_failure;
201
}
202
for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
203
doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
204
for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
205
doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
206
nla_for_each_nested(nla_a,
207
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
208
nla_a_rem)
209
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
210
struct nlattr *lvl_loc;
211
struct nlattr *lvl_rem;
212
213
lvl_loc = nla_find_nested(nla_a,
214
NLBL_CIPSOV4_A_MLSLVLLOC);
215
lvl_rem = nla_find_nested(nla_a,
216
NLBL_CIPSOV4_A_MLSLVLREM);
217
if (lvl_loc == NULL || lvl_rem == NULL)
218
goto add_std_failure;
219
doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
220
nla_get_u32(lvl_rem);
221
doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
222
nla_get_u32(lvl_loc);
223
}
224
225
if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
226
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
goto add_std_failure;
231
232
nla_for_each_nested(nla_a,
233
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
234
nla_a_rem)
235
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
236
if (nla_validate_nested_deprecated(nla_a,
237
NLBL_CIPSOV4_A_MAX,
238
netlbl_cipsov4_genl_policy,
239
NULL) != 0)
240
goto add_std_failure;
241
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
242
switch (nla_type(nla_b)) {
243
case NLBL_CIPSOV4_A_MLSCATLOC:
244
if (nla_get_u32(nla_b) >
245
CIPSO_V4_MAX_LOC_CATS)
246
goto add_std_failure;
247
if (nla_get_u32(nla_b) >=
248
doi_def->map.std->cat.local_size)
249
doi_def->map.std->cat.local_size =
250
nla_get_u32(nla_b) + 1;
251
break;
252
case NLBL_CIPSOV4_A_MLSCATREM:
253
if (nla_get_u32(nla_b) >
254
CIPSO_V4_MAX_REM_CATS)
255
goto add_std_failure;
256
if (nla_get_u32(nla_b) >=
257
doi_def->map.std->cat.cipso_size)
258
doi_def->map.std->cat.cipso_size =
259
nla_get_u32(nla_b) + 1;
260
break;
261
}
262
}
263
doi_def->map.std->cat.local = kcalloc(
264
doi_def->map.std->cat.local_size,
265
sizeof(u32),
266
GFP_KERNEL | __GFP_NOWARN);
267
if (doi_def->map.std->cat.local == NULL) {
268
ret_val = -ENOMEM;
269
goto add_std_failure;
270
}
271
doi_def->map.std->cat.cipso = kcalloc(
272
doi_def->map.std->cat.cipso_size,
273
sizeof(u32),
274
GFP_KERNEL | __GFP_NOWARN);
275
if (doi_def->map.std->cat.cipso == NULL) {
276
ret_val = -ENOMEM;
277
goto add_std_failure;
278
}
279
for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
280
doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
281
for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
282
doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
283
nla_for_each_nested(nla_a,
284
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
285
nla_a_rem)
286
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
287
struct nlattr *cat_loc;
288
struct nlattr *cat_rem;
289
290
cat_loc = nla_find_nested(nla_a,
291
NLBL_CIPSOV4_A_MLSCATLOC);
292
cat_rem = nla_find_nested(nla_a,
293
NLBL_CIPSOV4_A_MLSCATREM);
294
if (cat_loc == NULL || cat_rem == NULL)
295
goto add_std_failure;
296
doi_def->map.std->cat.local[
297
nla_get_u32(cat_loc)] =
298
nla_get_u32(cat_rem);
299
doi_def->map.std->cat.cipso[
300
nla_get_u32(cat_rem)] =
301
nla_get_u32(cat_loc);
302
}
303
}
304
305
ret_val = cipso_v4_doi_add(doi_def, audit_info);
306
if (ret_val != 0)
307
goto add_std_failure;
308
return 0;
309
310
add_std_failure:
311
cipso_v4_doi_free(doi_def);
312
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
static int netlbl_cipsov4_add_pass(struct genl_info *info,
327
struct netlbl_audit *audit_info)
328
{
329
int ret_val;
330
struct cipso_v4_doi *doi_def = NULL;
331
332
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
333
return -EINVAL;
334
335
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
336
if (doi_def == NULL)
337
return -ENOMEM;
338
doi_def->type = CIPSO_V4_MAP_PASS;
339
340
ret_val = netlbl_cipsov4_add_common(info, doi_def);
341
if (ret_val != 0)
342
goto add_pass_failure;
343
344
ret_val = cipso_v4_doi_add(doi_def, audit_info);
345
if (ret_val != 0)
346
goto add_pass_failure;
347
return 0;
348
349
add_pass_failure:
350
cipso_v4_doi_free(doi_def);
351
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
static int netlbl_cipsov4_add_local(struct genl_info *info,
366
struct netlbl_audit *audit_info)
367
{
368
int ret_val;
369
struct cipso_v4_doi *doi_def = NULL;
370
371
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
372
return -EINVAL;
373
374
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
375
if (doi_def == NULL)
376
return -ENOMEM;
377
doi_def->type = CIPSO_V4_MAP_LOCAL;
378
379
ret_val = netlbl_cipsov4_add_common(info, doi_def);
380
if (ret_val != 0)
381
goto add_local_failure;
382
383
ret_val = cipso_v4_doi_add(doi_def, audit_info);
384
if (ret_val != 0)
385
goto add_local_failure;
386
return 0;
387
388
add_local_failure:
389
cipso_v4_doi_free(doi_def);
390
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
static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
404
405
{
406
int ret_val = -EINVAL;
407
struct netlbl_audit audit_info;
408
409
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
410
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
411
return -EINVAL;
412
413
netlbl_netlink_auditinfo(&audit_info);
414
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
415
case CIPSO_V4_MAP_TRANS:
416
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
417
break;
418
case CIPSO_V4_MAP_PASS:
419
ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
420
break;
421
case CIPSO_V4_MAP_LOCAL:
422
ret_val = netlbl_cipsov4_add_local(info, &audit_info);
423
break;
424
}
425
if (ret_val == 0)
426
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
static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
449
{
450
int ret_val;
451
struct sk_buff *ans_skb = NULL;
452
u32 nlsze_mult = 1;
453
void *data;
454
u32 doi;
455
struct nlattr *nla_a;
456
struct nlattr *nla_b;
457
struct cipso_v4_doi *doi_def;
458
u32 iter;
459
460
if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
461
ret_val = -EINVAL;
462
goto list_failure;
463
}
464
465
list_start:
466
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
467
if (ans_skb == NULL) {
468
ret_val = -ENOMEM;
469
goto list_failure;
470
}
471
data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
472
0, NLBL_CIPSOV4_C_LIST);
473
if (data == NULL) {
474
ret_val = -ENOMEM;
475
goto list_failure;
476
}
477
478
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
479
480
rcu_read_lock();
481
doi_def = cipso_v4_doi_getdef(doi);
482
if (doi_def == NULL) {
483
ret_val = -EINVAL;
484
goto list_failure_lock;
485
}
486
487
ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
488
if (ret_val != 0)
489
goto list_failure_lock;
490
491
nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
492
if (nla_a == NULL) {
493
ret_val = -ENOMEM;
494
goto list_failure_lock;
495
}
496
for (iter = 0;
497
iter < CIPSO_V4_TAG_MAXCNT &&
498
doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
499
iter++) {
500
ret_val = nla_put_u8(ans_skb,
501
NLBL_CIPSOV4_A_TAG,
502
doi_def->tags[iter]);
503
if (ret_val != 0)
504
goto list_failure_lock;
505
}
506
nla_nest_end(ans_skb, nla_a);
507
508
switch (doi_def->type) {
509
case CIPSO_V4_MAP_TRANS:
510
nla_a = nla_nest_start_noflag(ans_skb,
511
NLBL_CIPSOV4_A_MLSLVLLST);
512
if (nla_a == NULL) {
513
ret_val = -ENOMEM;
514
goto list_failure_lock;
515
}
516
for (iter = 0;
517
iter < doi_def->map.std->lvl.local_size;
518
iter++) {
519
if (doi_def->map.std->lvl.local[iter] ==
520
CIPSO_V4_INV_LVL)
521
continue;
522
523
nla_b = nla_nest_start_noflag(ans_skb,
524
NLBL_CIPSOV4_A_MLSLVL);
525
if (nla_b == NULL) {
526
ret_val = -ENOMEM;
527
goto list_retry;
528
}
529
ret_val = nla_put_u32(ans_skb,
530
NLBL_CIPSOV4_A_MLSLVLLOC,
531
iter);
532
if (ret_val != 0)
533
goto list_retry;
534
ret_val = nla_put_u32(ans_skb,
535
NLBL_CIPSOV4_A_MLSLVLREM,
536
doi_def->map.std->lvl.local[iter]);
537
if (ret_val != 0)
538
goto list_retry;
539
nla_nest_end(ans_skb, nla_b);
540
}
541
nla_nest_end(ans_skb, nla_a);
542
543
nla_a = nla_nest_start_noflag(ans_skb,
544
NLBL_CIPSOV4_A_MLSCATLST);
545
if (nla_a == NULL) {
546
ret_val = -ENOMEM;
547
goto list_retry;
548
}
549
for (iter = 0;
550
iter < doi_def->map.std->cat.local_size;
551
iter++) {
552
if (doi_def->map.std->cat.local[iter] ==
553
CIPSO_V4_INV_CAT)
554
continue;
555
556
nla_b = nla_nest_start_noflag(ans_skb,
557
NLBL_CIPSOV4_A_MLSCAT);
558
if (nla_b == NULL) {
559
ret_val = -ENOMEM;
560
goto list_retry;
561
}
562
ret_val = nla_put_u32(ans_skb,
563
NLBL_CIPSOV4_A_MLSCATLOC,
564
iter);
565
if (ret_val != 0)
566
goto list_retry;
567
ret_val = nla_put_u32(ans_skb,
568
NLBL_CIPSOV4_A_MLSCATREM,
569
doi_def->map.std->cat.local[iter]);
570
if (ret_val != 0)
571
goto list_retry;
572
nla_nest_end(ans_skb, nla_b);
573
}
574
nla_nest_end(ans_skb, nla_a);
575
576
break;
577
}
578
cipso_v4_doi_putdef(doi_def);
579
rcu_read_unlock();
580
581
genlmsg_end(ans_skb, data);
582
return genlmsg_reply(ans_skb, info);
583
584
list_retry:
585
/* XXX - this limit is a guesstimate */
586
if (nlsze_mult < 4) {
587
cipso_v4_doi_putdef(doi_def);
588
rcu_read_unlock();
589
kfree_skb(ans_skb);
590
nlsze_mult *= 2;
591
goto list_start;
592
}
593
list_failure_lock:
594
cipso_v4_doi_putdef(doi_def);
595
rcu_read_unlock();
596
list_failure:
597
kfree_skb(ans_skb);
598
return ret_val;
599
}
600
601
/**
602
* netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
603
* @doi_def: the CIPSOv4 DOI definition
604
* @arg: the netlbl_cipsov4_doiwalk_arg structure
605
*
606
* Description:
607
* This function is designed to be used as a callback to the
608
* cipso_v4_doi_walk() function for use in generating a response for a LISTALL
609
* message. Returns the size of the message on success, negative values on
610
* failure.
611
*
612
*/
613
static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
614
{
615
int ret_val = -ENOMEM;
616
struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
617
void *data;
618
619
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
620
cb_arg->seq, &netlbl_cipsov4_gnl_family,
621
NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
622
if (data == NULL)
623
goto listall_cb_failure;
624
625
ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
626
if (ret_val != 0)
627
goto listall_cb_failure;
628
ret_val = nla_put_u32(cb_arg->skb,
629
NLBL_CIPSOV4_A_MTYPE,
630
doi_def->type);
631
if (ret_val != 0)
632
goto listall_cb_failure;
633
634
genlmsg_end(cb_arg->skb, data);
635
return 0;
636
637
listall_cb_failure:
638
genlmsg_cancel(cb_arg->skb, data);
639
return ret_val;
640
}
641
642
/**
643
* netlbl_cipsov4_listall - Handle a LISTALL message
644
* @skb: the NETLINK buffer
645
* @cb: the NETLINK callback
646
*
647
* Description:
648
* Process a user generated LISTALL message and respond accordingly. Returns
649
* zero on success and negative values on error.
650
*
651
*/
652
static int netlbl_cipsov4_listall(struct sk_buff *skb,
653
struct netlink_callback *cb)
654
{
655
struct netlbl_cipsov4_doiwalk_arg cb_arg;
656
u32 doi_skip = cb->args[0];
657
658
cb_arg.nl_cb = cb;
659
cb_arg.skb = skb;
660
cb_arg.seq = cb->nlh->nlmsg_seq;
661
662
cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
663
664
cb->args[0] = doi_skip;
665
return skb->len;
666
}
667
668
/**
669
* netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
670
* @entry: LSM domain mapping entry
671
* @arg: the netlbl_domhsh_walk_arg structure
672
*
673
* Description:
674
* This function is intended for use by netlbl_cipsov4_remove() as the callback
675
* for the netlbl_domhsh_walk() function; it removes LSM domain map entries
676
* which are associated with the CIPSO DOI specified in @arg. Returns zero on
677
* success, negative values on failure.
678
*
679
*/
680
static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
681
{
682
struct netlbl_domhsh_walk_arg *cb_arg = arg;
683
684
if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
685
entry->def.cipso->doi == cb_arg->doi)
686
return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
687
688
return 0;
689
}
690
691
/**
692
* netlbl_cipsov4_remove - Handle a REMOVE message
693
* @skb: the NETLINK buffer
694
* @info: the Generic NETLINK info block
695
*
696
* Description:
697
* Process a user generated REMOVE message and respond accordingly. Returns
698
* zero on success, negative values on failure.
699
*
700
*/
701
static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
702
{
703
int ret_val = -EINVAL;
704
struct netlbl_domhsh_walk_arg cb_arg;
705
struct netlbl_audit audit_info;
706
u32 skip_bkt = 0;
707
u32 skip_chain = 0;
708
709
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
710
return -EINVAL;
711
712
netlbl_netlink_auditinfo(&audit_info);
713
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
714
cb_arg.audit_info = &audit_info;
715
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
716
netlbl_cipsov4_remove_cb, &cb_arg);
717
if (ret_val == 0 || ret_val == -ENOENT) {
718
ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
719
if (ret_val == 0)
720
atomic_dec(&netlabel_mgmt_protocount);
721
}
722
723
return ret_val;
724
}
725
726
/*
727
* NetLabel Generic NETLINK Command Definitions
728
*/
729
730
static const struct genl_small_ops netlbl_cipsov4_ops[] = {
731
{
732
.cmd = NLBL_CIPSOV4_C_ADD,
733
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
734
.flags = GENL_ADMIN_PERM,
735
.doit = netlbl_cipsov4_add,
736
.dumpit = NULL,
737
},
738
{
739
.cmd = NLBL_CIPSOV4_C_REMOVE,
740
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
741
.flags = GENL_ADMIN_PERM,
742
.doit = netlbl_cipsov4_remove,
743
.dumpit = NULL,
744
},
745
{
746
.cmd = NLBL_CIPSOV4_C_LIST,
747
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
748
.flags = 0,
749
.doit = netlbl_cipsov4_list,
750
.dumpit = NULL,
751
},
752
{
753
.cmd = NLBL_CIPSOV4_C_LISTALL,
754
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
755
.flags = 0,
756
.doit = NULL,
757
.dumpit = netlbl_cipsov4_listall,
758
},
759
};
760
761
static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
762
.hdrsize = 0,
763
.name = NETLBL_NLTYPE_CIPSOV4_NAME,
764
.version = NETLBL_PROTO_VERSION,
765
.maxattr = NLBL_CIPSOV4_A_MAX,
766
.policy = netlbl_cipsov4_genl_policy,
767
.module = THIS_MODULE,
768
.small_ops = netlbl_cipsov4_ops,
769
.n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
770
.resv_start_op = NLBL_CIPSOV4_C_LISTALL + 1,
771
};
772
773
/*
774
* NetLabel Generic NETLINK Protocol Functions
775
*/
776
777
/**
778
* netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
779
*
780
* Description:
781
* Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
782
* mechanism. Returns zero on success, negative values on failure.
783
*
784
*/
785
int __init netlbl_cipsov4_genl_init(void)
786
{
787
return genl_register_family(&netlbl_cipsov4_gnl_family);
788
}
789
790