Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/netlabel/netlabel_unlabeled.c
15109 views
1
/*
2
* NetLabel Unlabeled Support
3
*
4
* This file defines functions for dealing with unlabeled packets for the
5
* NetLabel system. The NetLabel system manages static and dynamic label
6
* mappings for network 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 - 2008
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/rcupdate.h>
33
#include <linux/list.h>
34
#include <linux/spinlock.h>
35
#include <linux/socket.h>
36
#include <linux/string.h>
37
#include <linux/skbuff.h>
38
#include <linux/audit.h>
39
#include <linux/in.h>
40
#include <linux/in6.h>
41
#include <linux/ip.h>
42
#include <linux/ipv6.h>
43
#include <linux/notifier.h>
44
#include <linux/netdevice.h>
45
#include <linux/security.h>
46
#include <linux/slab.h>
47
#include <net/sock.h>
48
#include <net/netlink.h>
49
#include <net/genetlink.h>
50
#include <net/ip.h>
51
#include <net/ipv6.h>
52
#include <net/net_namespace.h>
53
#include <net/netlabel.h>
54
#include <asm/bug.h>
55
#include <asm/atomic.h>
56
57
#include "netlabel_user.h"
58
#include "netlabel_addrlist.h"
59
#include "netlabel_domainhash.h"
60
#include "netlabel_unlabeled.h"
61
#include "netlabel_mgmt.h"
62
63
/* NOTE: at present we always use init's network namespace since we don't
64
* presently support different namespaces even though the majority of
65
* the functions in this file are "namespace safe" */
66
67
/* The unlabeled connection hash table which we use to map network interfaces
68
* and addresses of unlabeled packets to a user specified secid value for the
69
* LSM. The hash table is used to lookup the network interface entry
70
* (struct netlbl_unlhsh_iface) and then the interface entry is used to
71
* lookup an IP address match from an ordered list. If a network interface
72
* match can not be found in the hash table then the default entry
73
* (netlbl_unlhsh_def) is used. The IP address entry list
74
* (struct netlbl_unlhsh_addr) is ordered such that the entries with a
75
* larger netmask come first.
76
*/
77
struct netlbl_unlhsh_tbl {
78
struct list_head *tbl;
79
u32 size;
80
};
81
#define netlbl_unlhsh_addr4_entry(iter) \
82
container_of(iter, struct netlbl_unlhsh_addr4, list)
83
struct netlbl_unlhsh_addr4 {
84
u32 secid;
85
86
struct netlbl_af4list list;
87
struct rcu_head rcu;
88
};
89
#define netlbl_unlhsh_addr6_entry(iter) \
90
container_of(iter, struct netlbl_unlhsh_addr6, list)
91
struct netlbl_unlhsh_addr6 {
92
u32 secid;
93
94
struct netlbl_af6list list;
95
struct rcu_head rcu;
96
};
97
struct netlbl_unlhsh_iface {
98
int ifindex;
99
struct list_head addr4_list;
100
struct list_head addr6_list;
101
102
u32 valid;
103
struct list_head list;
104
struct rcu_head rcu;
105
};
106
107
/* Argument struct for netlbl_unlhsh_walk() */
108
struct netlbl_unlhsh_walk_arg {
109
struct netlink_callback *nl_cb;
110
struct sk_buff *skb;
111
u32 seq;
112
};
113
114
/* Unlabeled connection hash table */
115
/* updates should be so rare that having one spinlock for the entire
116
* hash table should be okay */
117
static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
118
#define netlbl_unlhsh_rcu_deref(p) \
119
rcu_dereference_check(p, rcu_read_lock_held() || \
120
lockdep_is_held(&netlbl_unlhsh_lock))
121
static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;
122
static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;
123
124
/* Accept unlabeled packets flag */
125
static u8 netlabel_unlabel_acceptflg = 0;
126
127
/* NetLabel Generic NETLINK unlabeled family */
128
static struct genl_family netlbl_unlabel_gnl_family = {
129
.id = GENL_ID_GENERATE,
130
.hdrsize = 0,
131
.name = NETLBL_NLTYPE_UNLABELED_NAME,
132
.version = NETLBL_PROTO_VERSION,
133
.maxattr = NLBL_UNLABEL_A_MAX,
134
};
135
136
/* NetLabel Netlink attribute policy */
137
static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
138
[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
139
[NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,
140
.len = sizeof(struct in6_addr) },
141
[NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,
142
.len = sizeof(struct in6_addr) },
143
[NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,
144
.len = sizeof(struct in_addr) },
145
[NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,
146
.len = sizeof(struct in_addr) },
147
[NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,
148
.len = IFNAMSIZ - 1 },
149
[NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
150
};
151
152
/*
153
* Unlabeled Connection Hash Table Functions
154
*/
155
156
/**
157
* netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
158
* @entry: the entry's RCU field
159
*
160
* Description:
161
* This function is designed to be used as a callback to the call_rcu()
162
* function so that memory allocated to a hash table interface entry can be
163
* released safely. It is important to note that this function does not free
164
* the IPv4 and IPv6 address lists contained as part of an interface entry. It
165
* is up to the rest of the code to make sure an interface entry is only freed
166
* once it's address lists are empty.
167
*
168
*/
169
static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
170
{
171
struct netlbl_unlhsh_iface *iface;
172
struct netlbl_af4list *iter4;
173
struct netlbl_af4list *tmp4;
174
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
175
struct netlbl_af6list *iter6;
176
struct netlbl_af6list *tmp6;
177
#endif /* IPv6 */
178
179
iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
180
181
/* no need for locks here since we are the only one with access to this
182
* structure */
183
184
netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
185
netlbl_af4list_remove_entry(iter4);
186
kfree(netlbl_unlhsh_addr4_entry(iter4));
187
}
188
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
189
netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
190
netlbl_af6list_remove_entry(iter6);
191
kfree(netlbl_unlhsh_addr6_entry(iter6));
192
}
193
#endif /* IPv6 */
194
kfree(iface);
195
}
196
197
/**
198
* netlbl_unlhsh_hash - Hashing function for the hash table
199
* @ifindex: the network interface/device to hash
200
*
201
* Description:
202
* This is the hashing function for the unlabeled hash table, it returns the
203
* bucket number for the given device/interface. The caller is responsible for
204
* ensuring that the hash table is protected with either a RCU read lock or
205
* the hash table lock.
206
*
207
*/
208
static u32 netlbl_unlhsh_hash(int ifindex)
209
{
210
return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1);
211
}
212
213
/**
214
* netlbl_unlhsh_search_iface - Search for a matching interface entry
215
* @ifindex: the network interface
216
*
217
* Description:
218
* Searches the unlabeled connection hash table and returns a pointer to the
219
* interface entry which matches @ifindex, otherwise NULL is returned. The
220
* caller is responsible for ensuring that the hash table is protected with
221
* either a RCU read lock or the hash table lock.
222
*
223
*/
224
static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
225
{
226
u32 bkt;
227
struct list_head *bkt_list;
228
struct netlbl_unlhsh_iface *iter;
229
230
bkt = netlbl_unlhsh_hash(ifindex);
231
bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt];
232
list_for_each_entry_rcu(iter, bkt_list, list)
233
if (iter->valid && iter->ifindex == ifindex)
234
return iter;
235
236
return NULL;
237
}
238
239
/**
240
* netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table
241
* @iface: the associated interface entry
242
* @addr: IPv4 address in network byte order
243
* @mask: IPv4 address mask in network byte order
244
* @secid: LSM secid value for entry
245
*
246
* Description:
247
* Add a new address entry into the unlabeled connection hash table using the
248
* interface entry specified by @iface. On success zero is returned, otherwise
249
* a negative value is returned.
250
*
251
*/
252
static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
253
const struct in_addr *addr,
254
const struct in_addr *mask,
255
u32 secid)
256
{
257
int ret_val;
258
struct netlbl_unlhsh_addr4 *entry;
259
260
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
261
if (entry == NULL)
262
return -ENOMEM;
263
264
entry->list.addr = addr->s_addr & mask->s_addr;
265
entry->list.mask = mask->s_addr;
266
entry->list.valid = 1;
267
entry->secid = secid;
268
269
spin_lock(&netlbl_unlhsh_lock);
270
ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
271
spin_unlock(&netlbl_unlhsh_lock);
272
273
if (ret_val != 0)
274
kfree(entry);
275
return ret_val;
276
}
277
278
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
279
/**
280
* netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table
281
* @iface: the associated interface entry
282
* @addr: IPv6 address in network byte order
283
* @mask: IPv6 address mask in network byte order
284
* @secid: LSM secid value for entry
285
*
286
* Description:
287
* Add a new address entry into the unlabeled connection hash table using the
288
* interface entry specified by @iface. On success zero is returned, otherwise
289
* a negative value is returned.
290
*
291
*/
292
static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
293
const struct in6_addr *addr,
294
const struct in6_addr *mask,
295
u32 secid)
296
{
297
int ret_val;
298
struct netlbl_unlhsh_addr6 *entry;
299
300
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
301
if (entry == NULL)
302
return -ENOMEM;
303
304
ipv6_addr_copy(&entry->list.addr, addr);
305
entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
306
entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
307
entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
308
entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
309
ipv6_addr_copy(&entry->list.mask, mask);
310
entry->list.valid = 1;
311
entry->secid = secid;
312
313
spin_lock(&netlbl_unlhsh_lock);
314
ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
315
spin_unlock(&netlbl_unlhsh_lock);
316
317
if (ret_val != 0)
318
kfree(entry);
319
return 0;
320
}
321
#endif /* IPv6 */
322
323
/**
324
* netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table
325
* @ifindex: network interface
326
*
327
* Description:
328
* Add a new, empty, interface entry into the unlabeled connection hash table.
329
* On success a pointer to the new interface entry is returned, on failure NULL
330
* is returned.
331
*
332
*/
333
static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
334
{
335
u32 bkt;
336
struct netlbl_unlhsh_iface *iface;
337
338
iface = kzalloc(sizeof(*iface), GFP_ATOMIC);
339
if (iface == NULL)
340
return NULL;
341
342
iface->ifindex = ifindex;
343
INIT_LIST_HEAD(&iface->addr4_list);
344
INIT_LIST_HEAD(&iface->addr6_list);
345
iface->valid = 1;
346
347
spin_lock(&netlbl_unlhsh_lock);
348
if (ifindex > 0) {
349
bkt = netlbl_unlhsh_hash(ifindex);
350
if (netlbl_unlhsh_search_iface(ifindex) != NULL)
351
goto add_iface_failure;
352
list_add_tail_rcu(&iface->list,
353
&netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]);
354
} else {
355
INIT_LIST_HEAD(&iface->list);
356
if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)
357
goto add_iface_failure;
358
rcu_assign_pointer(netlbl_unlhsh_def, iface);
359
}
360
spin_unlock(&netlbl_unlhsh_lock);
361
362
return iface;
363
364
add_iface_failure:
365
spin_unlock(&netlbl_unlhsh_lock);
366
kfree(iface);
367
return NULL;
368
}
369
370
/**
371
* netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table
372
* @net: network namespace
373
* @dev_name: interface name
374
* @addr: IP address in network byte order
375
* @mask: address mask in network byte order
376
* @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
377
* @secid: LSM secid value for the entry
378
* @audit_info: NetLabel audit information
379
*
380
* Description:
381
* Adds a new entry to the unlabeled connection hash table. Returns zero on
382
* success, negative values on failure.
383
*
384
*/
385
int netlbl_unlhsh_add(struct net *net,
386
const char *dev_name,
387
const void *addr,
388
const void *mask,
389
u32 addr_len,
390
u32 secid,
391
struct netlbl_audit *audit_info)
392
{
393
int ret_val;
394
int ifindex;
395
struct net_device *dev;
396
struct netlbl_unlhsh_iface *iface;
397
struct audit_buffer *audit_buf = NULL;
398
char *secctx = NULL;
399
u32 secctx_len;
400
401
if (addr_len != sizeof(struct in_addr) &&
402
addr_len != sizeof(struct in6_addr))
403
return -EINVAL;
404
405
rcu_read_lock();
406
if (dev_name != NULL) {
407
dev = dev_get_by_name_rcu(net, dev_name);
408
if (dev == NULL) {
409
ret_val = -ENODEV;
410
goto unlhsh_add_return;
411
}
412
ifindex = dev->ifindex;
413
iface = netlbl_unlhsh_search_iface(ifindex);
414
} else {
415
ifindex = 0;
416
iface = rcu_dereference(netlbl_unlhsh_def);
417
}
418
if (iface == NULL) {
419
iface = netlbl_unlhsh_add_iface(ifindex);
420
if (iface == NULL) {
421
ret_val = -ENOMEM;
422
goto unlhsh_add_return;
423
}
424
}
425
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
426
audit_info);
427
switch (addr_len) {
428
case sizeof(struct in_addr): {
429
struct in_addr *addr4, *mask4;
430
431
addr4 = (struct in_addr *)addr;
432
mask4 = (struct in_addr *)mask;
433
ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
434
if (audit_buf != NULL)
435
netlbl_af4list_audit_addr(audit_buf, 1,
436
dev_name,
437
addr4->s_addr,
438
mask4->s_addr);
439
break;
440
}
441
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
442
case sizeof(struct in6_addr): {
443
struct in6_addr *addr6, *mask6;
444
445
addr6 = (struct in6_addr *)addr;
446
mask6 = (struct in6_addr *)mask;
447
ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
448
if (audit_buf != NULL)
449
netlbl_af6list_audit_addr(audit_buf, 1,
450
dev_name,
451
addr6, mask6);
452
break;
453
}
454
#endif /* IPv6 */
455
default:
456
ret_val = -EINVAL;
457
}
458
if (ret_val == 0)
459
atomic_inc(&netlabel_mgmt_protocount);
460
461
unlhsh_add_return:
462
rcu_read_unlock();
463
if (audit_buf != NULL) {
464
if (security_secid_to_secctx(secid,
465
&secctx,
466
&secctx_len) == 0) {
467
audit_log_format(audit_buf, " sec_obj=%s", secctx);
468
security_release_secctx(secctx, secctx_len);
469
}
470
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
471
audit_log_end(audit_buf);
472
}
473
return ret_val;
474
}
475
476
/**
477
* netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
478
* @net: network namespace
479
* @iface: interface entry
480
* @addr: IP address
481
* @mask: IP address mask
482
* @audit_info: NetLabel audit information
483
*
484
* Description:
485
* Remove an IP address entry from the unlabeled connection hash table.
486
* Returns zero on success, negative values on failure.
487
*
488
*/
489
static int netlbl_unlhsh_remove_addr4(struct net *net,
490
struct netlbl_unlhsh_iface *iface,
491
const struct in_addr *addr,
492
const struct in_addr *mask,
493
struct netlbl_audit *audit_info)
494
{
495
struct netlbl_af4list *list_entry;
496
struct netlbl_unlhsh_addr4 *entry;
497
struct audit_buffer *audit_buf;
498
struct net_device *dev;
499
char *secctx;
500
u32 secctx_len;
501
502
spin_lock(&netlbl_unlhsh_lock);
503
list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
504
&iface->addr4_list);
505
spin_unlock(&netlbl_unlhsh_lock);
506
if (list_entry != NULL)
507
entry = netlbl_unlhsh_addr4_entry(list_entry);
508
else
509
entry = NULL;
510
511
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
512
audit_info);
513
if (audit_buf != NULL) {
514
dev = dev_get_by_index(net, iface->ifindex);
515
netlbl_af4list_audit_addr(audit_buf, 1,
516
(dev != NULL ? dev->name : NULL),
517
addr->s_addr, mask->s_addr);
518
if (dev != NULL)
519
dev_put(dev);
520
if (entry != NULL &&
521
security_secid_to_secctx(entry->secid,
522
&secctx, &secctx_len) == 0) {
523
audit_log_format(audit_buf, " sec_obj=%s", secctx);
524
security_release_secctx(secctx, secctx_len);
525
}
526
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
527
audit_log_end(audit_buf);
528
}
529
530
if (entry == NULL)
531
return -ENOENT;
532
533
kfree_rcu(entry, rcu);
534
return 0;
535
}
536
537
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
538
/**
539
* netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
540
* @net: network namespace
541
* @iface: interface entry
542
* @addr: IP address
543
* @mask: IP address mask
544
* @audit_info: NetLabel audit information
545
*
546
* Description:
547
* Remove an IP address entry from the unlabeled connection hash table.
548
* Returns zero on success, negative values on failure.
549
*
550
*/
551
static int netlbl_unlhsh_remove_addr6(struct net *net,
552
struct netlbl_unlhsh_iface *iface,
553
const struct in6_addr *addr,
554
const struct in6_addr *mask,
555
struct netlbl_audit *audit_info)
556
{
557
struct netlbl_af6list *list_entry;
558
struct netlbl_unlhsh_addr6 *entry;
559
struct audit_buffer *audit_buf;
560
struct net_device *dev;
561
char *secctx;
562
u32 secctx_len;
563
564
spin_lock(&netlbl_unlhsh_lock);
565
list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
566
spin_unlock(&netlbl_unlhsh_lock);
567
if (list_entry != NULL)
568
entry = netlbl_unlhsh_addr6_entry(list_entry);
569
else
570
entry = NULL;
571
572
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
573
audit_info);
574
if (audit_buf != NULL) {
575
dev = dev_get_by_index(net, iface->ifindex);
576
netlbl_af6list_audit_addr(audit_buf, 1,
577
(dev != NULL ? dev->name : NULL),
578
addr, mask);
579
if (dev != NULL)
580
dev_put(dev);
581
if (entry != NULL &&
582
security_secid_to_secctx(entry->secid,
583
&secctx, &secctx_len) == 0) {
584
audit_log_format(audit_buf, " sec_obj=%s", secctx);
585
security_release_secctx(secctx, secctx_len);
586
}
587
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
588
audit_log_end(audit_buf);
589
}
590
591
if (entry == NULL)
592
return -ENOENT;
593
594
kfree_rcu(entry, rcu);
595
return 0;
596
}
597
#endif /* IPv6 */
598
599
/**
600
* netlbl_unlhsh_condremove_iface - Remove an interface entry
601
* @iface: the interface entry
602
*
603
* Description:
604
* Remove an interface entry from the unlabeled connection hash table if it is
605
* empty. An interface entry is considered to be empty if there are no
606
* address entries assigned to it.
607
*
608
*/
609
static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
610
{
611
struct netlbl_af4list *iter4;
612
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
613
struct netlbl_af6list *iter6;
614
#endif /* IPv6 */
615
616
spin_lock(&netlbl_unlhsh_lock);
617
netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
618
goto unlhsh_condremove_failure;
619
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
620
netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
621
goto unlhsh_condremove_failure;
622
#endif /* IPv6 */
623
iface->valid = 0;
624
if (iface->ifindex > 0)
625
list_del_rcu(&iface->list);
626
else
627
rcu_assign_pointer(netlbl_unlhsh_def, NULL);
628
spin_unlock(&netlbl_unlhsh_lock);
629
630
call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
631
return;
632
633
unlhsh_condremove_failure:
634
spin_unlock(&netlbl_unlhsh_lock);
635
}
636
637
/**
638
* netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
639
* @net: network namespace
640
* @dev_name: interface name
641
* @addr: IP address in network byte order
642
* @mask: address mask in network byte order
643
* @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
644
* @audit_info: NetLabel audit information
645
*
646
* Description:
647
* Removes and existing entry from the unlabeled connection hash table.
648
* Returns zero on success, negative values on failure.
649
*
650
*/
651
int netlbl_unlhsh_remove(struct net *net,
652
const char *dev_name,
653
const void *addr,
654
const void *mask,
655
u32 addr_len,
656
struct netlbl_audit *audit_info)
657
{
658
int ret_val;
659
struct net_device *dev;
660
struct netlbl_unlhsh_iface *iface;
661
662
if (addr_len != sizeof(struct in_addr) &&
663
addr_len != sizeof(struct in6_addr))
664
return -EINVAL;
665
666
rcu_read_lock();
667
if (dev_name != NULL) {
668
dev = dev_get_by_name_rcu(net, dev_name);
669
if (dev == NULL) {
670
ret_val = -ENODEV;
671
goto unlhsh_remove_return;
672
}
673
iface = netlbl_unlhsh_search_iface(dev->ifindex);
674
} else
675
iface = rcu_dereference(netlbl_unlhsh_def);
676
if (iface == NULL) {
677
ret_val = -ENOENT;
678
goto unlhsh_remove_return;
679
}
680
switch (addr_len) {
681
case sizeof(struct in_addr):
682
ret_val = netlbl_unlhsh_remove_addr4(net,
683
iface, addr, mask,
684
audit_info);
685
break;
686
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
687
case sizeof(struct in6_addr):
688
ret_val = netlbl_unlhsh_remove_addr6(net,
689
iface, addr, mask,
690
audit_info);
691
break;
692
#endif /* IPv6 */
693
default:
694
ret_val = -EINVAL;
695
}
696
if (ret_val == 0) {
697
netlbl_unlhsh_condremove_iface(iface);
698
atomic_dec(&netlabel_mgmt_protocount);
699
}
700
701
unlhsh_remove_return:
702
rcu_read_unlock();
703
return ret_val;
704
}
705
706
/*
707
* General Helper Functions
708
*/
709
710
/**
711
* netlbl_unlhsh_netdev_handler - Network device notification handler
712
* @this: notifier block
713
* @event: the event
714
* @ptr: the network device (cast to void)
715
*
716
* Description:
717
* Handle network device events, although at present all we care about is a
718
* network device going away. In the case of a device going away we clear any
719
* related entries from the unlabeled connection hash table.
720
*
721
*/
722
static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
723
unsigned long event,
724
void *ptr)
725
{
726
struct net_device *dev = ptr;
727
struct netlbl_unlhsh_iface *iface = NULL;
728
729
if (!net_eq(dev_net(dev), &init_net))
730
return NOTIFY_DONE;
731
732
/* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
733
if (event == NETDEV_DOWN) {
734
spin_lock(&netlbl_unlhsh_lock);
735
iface = netlbl_unlhsh_search_iface(dev->ifindex);
736
if (iface != NULL && iface->valid) {
737
iface->valid = 0;
738
list_del_rcu(&iface->list);
739
} else
740
iface = NULL;
741
spin_unlock(&netlbl_unlhsh_lock);
742
}
743
744
if (iface != NULL)
745
call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
746
747
return NOTIFY_DONE;
748
}
749
750
/**
751
* netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
752
* @value: desired value
753
* @audit_info: NetLabel audit information
754
*
755
* Description:
756
* Set the value of the unlabeled accept flag to @value.
757
*
758
*/
759
static void netlbl_unlabel_acceptflg_set(u8 value,
760
struct netlbl_audit *audit_info)
761
{
762
struct audit_buffer *audit_buf;
763
u8 old_val;
764
765
old_val = netlabel_unlabel_acceptflg;
766
netlabel_unlabel_acceptflg = value;
767
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
768
audit_info);
769
if (audit_buf != NULL) {
770
audit_log_format(audit_buf,
771
" unlbl_accept=%u old=%u", value, old_val);
772
audit_log_end(audit_buf);
773
}
774
}
775
776
/**
777
* netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
778
* @info: the Generic NETLINK info block
779
* @addr: the IP address
780
* @mask: the IP address mask
781
* @len: the address length
782
*
783
* Description:
784
* Examine the Generic NETLINK message and extract the IP address information.
785
* Returns zero on success, negative values on failure.
786
*
787
*/
788
static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
789
void **addr,
790
void **mask,
791
u32 *len)
792
{
793
u32 addr_len;
794
795
if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR]) {
796
addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
797
if (addr_len != sizeof(struct in_addr) &&
798
addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
799
return -EINVAL;
800
*len = addr_len;
801
*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
802
*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
803
return 0;
804
} else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
805
addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
806
if (addr_len != sizeof(struct in6_addr) &&
807
addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
808
return -EINVAL;
809
*len = addr_len;
810
*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
811
*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
812
return 0;
813
}
814
815
return -EINVAL;
816
}
817
818
/*
819
* NetLabel Command Handlers
820
*/
821
822
/**
823
* netlbl_unlabel_accept - Handle an ACCEPT message
824
* @skb: the NETLINK buffer
825
* @info: the Generic NETLINK info block
826
*
827
* Description:
828
* Process a user generated ACCEPT message and set the accept flag accordingly.
829
* Returns zero on success, negative values on failure.
830
*
831
*/
832
static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
833
{
834
u8 value;
835
struct netlbl_audit audit_info;
836
837
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
838
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
839
if (value == 1 || value == 0) {
840
netlbl_netlink_auditinfo(skb, &audit_info);
841
netlbl_unlabel_acceptflg_set(value, &audit_info);
842
return 0;
843
}
844
}
845
846
return -EINVAL;
847
}
848
849
/**
850
* netlbl_unlabel_list - Handle a LIST message
851
* @skb: the NETLINK buffer
852
* @info: the Generic NETLINK info block
853
*
854
* Description:
855
* Process a user generated LIST message and respond with the current status.
856
* Returns zero on success, negative values on failure.
857
*
858
*/
859
static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
860
{
861
int ret_val = -EINVAL;
862
struct sk_buff *ans_skb;
863
void *data;
864
865
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
866
if (ans_skb == NULL)
867
goto list_failure;
868
data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,
869
0, NLBL_UNLABEL_C_LIST);
870
if (data == NULL) {
871
ret_val = -ENOMEM;
872
goto list_failure;
873
}
874
875
ret_val = nla_put_u8(ans_skb,
876
NLBL_UNLABEL_A_ACPTFLG,
877
netlabel_unlabel_acceptflg);
878
if (ret_val != 0)
879
goto list_failure;
880
881
genlmsg_end(ans_skb, data);
882
return genlmsg_reply(ans_skb, info);
883
884
list_failure:
885
kfree_skb(ans_skb);
886
return ret_val;
887
}
888
889
/**
890
* netlbl_unlabel_staticadd - Handle a STATICADD message
891
* @skb: the NETLINK buffer
892
* @info: the Generic NETLINK info block
893
*
894
* Description:
895
* Process a user generated STATICADD message and add a new unlabeled
896
* connection entry to the hash table. Returns zero on success, negative
897
* values on failure.
898
*
899
*/
900
static int netlbl_unlabel_staticadd(struct sk_buff *skb,
901
struct genl_info *info)
902
{
903
int ret_val;
904
char *dev_name;
905
void *addr;
906
void *mask;
907
u32 addr_len;
908
u32 secid;
909
struct netlbl_audit audit_info;
910
911
/* Don't allow users to add both IPv4 and IPv6 addresses for a
912
* single entry. However, allow users to create two entries, one each
913
* for IPv4 and IPv4, with the same LSM security context which should
914
* achieve the same result. */
915
if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
916
!info->attrs[NLBL_UNLABEL_A_IFACE] ||
917
!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
918
!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
919
(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
920
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
921
return -EINVAL;
922
923
netlbl_netlink_auditinfo(skb, &audit_info);
924
925
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
926
if (ret_val != 0)
927
return ret_val;
928
dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
929
ret_val = security_secctx_to_secid(
930
nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
931
nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
932
&secid);
933
if (ret_val != 0)
934
return ret_val;
935
936
return netlbl_unlhsh_add(&init_net,
937
dev_name, addr, mask, addr_len, secid,
938
&audit_info);
939
}
940
941
/**
942
* netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
943
* @skb: the NETLINK buffer
944
* @info: the Generic NETLINK info block
945
*
946
* Description:
947
* Process a user generated STATICADDDEF message and add a new default
948
* unlabeled connection entry. Returns zero on success, negative values on
949
* failure.
950
*
951
*/
952
static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
953
struct genl_info *info)
954
{
955
int ret_val;
956
void *addr;
957
void *mask;
958
u32 addr_len;
959
u32 secid;
960
struct netlbl_audit audit_info;
961
962
/* Don't allow users to add both IPv4 and IPv6 addresses for a
963
* single entry. However, allow users to create two entries, one each
964
* for IPv4 and IPv6, with the same LSM security context which should
965
* achieve the same result. */
966
if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
967
!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
968
!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
969
(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
970
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
971
return -EINVAL;
972
973
netlbl_netlink_auditinfo(skb, &audit_info);
974
975
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
976
if (ret_val != 0)
977
return ret_val;
978
ret_val = security_secctx_to_secid(
979
nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
980
nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
981
&secid);
982
if (ret_val != 0)
983
return ret_val;
984
985
return netlbl_unlhsh_add(&init_net,
986
NULL, addr, mask, addr_len, secid,
987
&audit_info);
988
}
989
990
/**
991
* netlbl_unlabel_staticremove - Handle a STATICREMOVE message
992
* @skb: the NETLINK buffer
993
* @info: the Generic NETLINK info block
994
*
995
* Description:
996
* Process a user generated STATICREMOVE message and remove the specified
997
* unlabeled connection entry. Returns zero on success, negative values on
998
* failure.
999
*
1000
*/
1001
static int netlbl_unlabel_staticremove(struct sk_buff *skb,
1002
struct genl_info *info)
1003
{
1004
int ret_val;
1005
char *dev_name;
1006
void *addr;
1007
void *mask;
1008
u32 addr_len;
1009
struct netlbl_audit audit_info;
1010
1011
/* See the note in netlbl_unlabel_staticadd() about not allowing both
1012
* IPv4 and IPv6 in the same entry. */
1013
if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
1014
!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1015
!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1016
(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1017
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1018
return -EINVAL;
1019
1020
netlbl_netlink_auditinfo(skb, &audit_info);
1021
1022
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1023
if (ret_val != 0)
1024
return ret_val;
1025
dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1026
1027
return netlbl_unlhsh_remove(&init_net,
1028
dev_name, addr, mask, addr_len,
1029
&audit_info);
1030
}
1031
1032
/**
1033
* netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
1034
* @skb: the NETLINK buffer
1035
* @info: the Generic NETLINK info block
1036
*
1037
* Description:
1038
* Process a user generated STATICREMOVEDEF message and remove the default
1039
* unlabeled connection entry. Returns zero on success, negative values on
1040
* failure.
1041
*
1042
*/
1043
static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
1044
struct genl_info *info)
1045
{
1046
int ret_val;
1047
void *addr;
1048
void *mask;
1049
u32 addr_len;
1050
struct netlbl_audit audit_info;
1051
1052
/* See the note in netlbl_unlabel_staticadd() about not allowing both
1053
* IPv4 and IPv6 in the same entry. */
1054
if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1055
!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1056
(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1057
!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1058
return -EINVAL;
1059
1060
netlbl_netlink_auditinfo(skb, &audit_info);
1061
1062
ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1063
if (ret_val != 0)
1064
return ret_val;
1065
1066
return netlbl_unlhsh_remove(&init_net,
1067
NULL, addr, mask, addr_len,
1068
&audit_info);
1069
}
1070
1071
1072
/**
1073
* netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
1074
* @cmd: command/message
1075
* @iface: the interface entry
1076
* @addr4: the IPv4 address entry
1077
* @addr6: the IPv6 address entry
1078
* @arg: the netlbl_unlhsh_walk_arg structure
1079
*
1080
* Description:
1081
* This function is designed to be used to generate a response for a
1082
* STATICLIST or STATICLISTDEF message. When called either @addr4 or @addr6
1083
* can be specified, not both, the other unspecified entry should be set to
1084
* NULL by the caller. Returns the size of the message on success, negative
1085
* values on failure.
1086
*
1087
*/
1088
static int netlbl_unlabel_staticlist_gen(u32 cmd,
1089
const struct netlbl_unlhsh_iface *iface,
1090
const struct netlbl_unlhsh_addr4 *addr4,
1091
const struct netlbl_unlhsh_addr6 *addr6,
1092
void *arg)
1093
{
1094
int ret_val = -ENOMEM;
1095
struct netlbl_unlhsh_walk_arg *cb_arg = arg;
1096
struct net_device *dev;
1097
void *data;
1098
u32 secid;
1099
char *secctx;
1100
u32 secctx_len;
1101
1102
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
1103
cb_arg->seq, &netlbl_unlabel_gnl_family,
1104
NLM_F_MULTI, cmd);
1105
if (data == NULL)
1106
goto list_cb_failure;
1107
1108
if (iface->ifindex > 0) {
1109
dev = dev_get_by_index(&init_net, iface->ifindex);
1110
if (!dev) {
1111
ret_val = -ENODEV;
1112
goto list_cb_failure;
1113
}
1114
ret_val = nla_put_string(cb_arg->skb,
1115
NLBL_UNLABEL_A_IFACE, dev->name);
1116
dev_put(dev);
1117
if (ret_val != 0)
1118
goto list_cb_failure;
1119
}
1120
1121
if (addr4) {
1122
struct in_addr addr_struct;
1123
1124
addr_struct.s_addr = addr4->list.addr;
1125
ret_val = nla_put(cb_arg->skb,
1126
NLBL_UNLABEL_A_IPV4ADDR,
1127
sizeof(struct in_addr),
1128
&addr_struct);
1129
if (ret_val != 0)
1130
goto list_cb_failure;
1131
1132
addr_struct.s_addr = addr4->list.mask;
1133
ret_val = nla_put(cb_arg->skb,
1134
NLBL_UNLABEL_A_IPV4MASK,
1135
sizeof(struct in_addr),
1136
&addr_struct);
1137
if (ret_val != 0)
1138
goto list_cb_failure;
1139
1140
secid = addr4->secid;
1141
} else {
1142
ret_val = nla_put(cb_arg->skb,
1143
NLBL_UNLABEL_A_IPV6ADDR,
1144
sizeof(struct in6_addr),
1145
&addr6->list.addr);
1146
if (ret_val != 0)
1147
goto list_cb_failure;
1148
1149
ret_val = nla_put(cb_arg->skb,
1150
NLBL_UNLABEL_A_IPV6MASK,
1151
sizeof(struct in6_addr),
1152
&addr6->list.mask);
1153
if (ret_val != 0)
1154
goto list_cb_failure;
1155
1156
secid = addr6->secid;
1157
}
1158
1159
ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
1160
if (ret_val != 0)
1161
goto list_cb_failure;
1162
ret_val = nla_put(cb_arg->skb,
1163
NLBL_UNLABEL_A_SECCTX,
1164
secctx_len,
1165
secctx);
1166
security_release_secctx(secctx, secctx_len);
1167
if (ret_val != 0)
1168
goto list_cb_failure;
1169
1170
cb_arg->seq++;
1171
return genlmsg_end(cb_arg->skb, data);
1172
1173
list_cb_failure:
1174
genlmsg_cancel(cb_arg->skb, data);
1175
return ret_val;
1176
}
1177
1178
/**
1179
* netlbl_unlabel_staticlist - Handle a STATICLIST message
1180
* @skb: the NETLINK buffer
1181
* @cb: the NETLINK callback
1182
*
1183
* Description:
1184
* Process a user generated STATICLIST message and dump the unlabeled
1185
* connection hash table in a form suitable for use in a kernel generated
1186
* STATICLIST message. Returns the length of @skb.
1187
*
1188
*/
1189
static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1190
struct netlink_callback *cb)
1191
{
1192
struct netlbl_unlhsh_walk_arg cb_arg;
1193
u32 skip_bkt = cb->args[0];
1194
u32 skip_chain = cb->args[1];
1195
u32 skip_addr4 = cb->args[2];
1196
u32 skip_addr6 = cb->args[3];
1197
u32 iter_bkt;
1198
u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1199
struct netlbl_unlhsh_iface *iface;
1200
struct list_head *iter_list;
1201
struct netlbl_af4list *addr4;
1202
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1203
struct netlbl_af6list *addr6;
1204
#endif
1205
1206
cb_arg.nl_cb = cb;
1207
cb_arg.skb = skb;
1208
cb_arg.seq = cb->nlh->nlmsg_seq;
1209
1210
rcu_read_lock();
1211
for (iter_bkt = skip_bkt;
1212
iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1213
iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
1214
iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
1215
list_for_each_entry_rcu(iface, iter_list, list) {
1216
if (!iface->valid ||
1217
iter_chain++ < skip_chain)
1218
continue;
1219
netlbl_af4list_foreach_rcu(addr4,
1220
&iface->addr4_list) {
1221
if (iter_addr4++ < skip_addr4)
1222
continue;
1223
if (netlbl_unlabel_staticlist_gen(
1224
NLBL_UNLABEL_C_STATICLIST,
1225
iface,
1226
netlbl_unlhsh_addr4_entry(addr4),
1227
NULL,
1228
&cb_arg) < 0) {
1229
iter_addr4--;
1230
iter_chain--;
1231
goto unlabel_staticlist_return;
1232
}
1233
}
1234
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1235
netlbl_af6list_foreach_rcu(addr6,
1236
&iface->addr6_list) {
1237
if (iter_addr6++ < skip_addr6)
1238
continue;
1239
if (netlbl_unlabel_staticlist_gen(
1240
NLBL_UNLABEL_C_STATICLIST,
1241
iface,
1242
NULL,
1243
netlbl_unlhsh_addr6_entry(addr6),
1244
&cb_arg) < 0) {
1245
iter_addr6--;
1246
iter_chain--;
1247
goto unlabel_staticlist_return;
1248
}
1249
}
1250
#endif /* IPv6 */
1251
}
1252
}
1253
1254
unlabel_staticlist_return:
1255
rcu_read_unlock();
1256
cb->args[0] = skip_bkt;
1257
cb->args[1] = skip_chain;
1258
cb->args[2] = skip_addr4;
1259
cb->args[3] = skip_addr6;
1260
return skb->len;
1261
}
1262
1263
/**
1264
* netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
1265
* @skb: the NETLINK buffer
1266
* @cb: the NETLINK callback
1267
*
1268
* Description:
1269
* Process a user generated STATICLISTDEF message and dump the default
1270
* unlabeled connection entry in a form suitable for use in a kernel generated
1271
* STATICLISTDEF message. Returns the length of @skb.
1272
*
1273
*/
1274
static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1275
struct netlink_callback *cb)
1276
{
1277
struct netlbl_unlhsh_walk_arg cb_arg;
1278
struct netlbl_unlhsh_iface *iface;
1279
u32 skip_addr4 = cb->args[0];
1280
u32 skip_addr6 = cb->args[1];
1281
u32 iter_addr4 = 0;
1282
struct netlbl_af4list *addr4;
1283
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1284
u32 iter_addr6 = 0;
1285
struct netlbl_af6list *addr6;
1286
#endif
1287
1288
cb_arg.nl_cb = cb;
1289
cb_arg.skb = skb;
1290
cb_arg.seq = cb->nlh->nlmsg_seq;
1291
1292
rcu_read_lock();
1293
iface = rcu_dereference(netlbl_unlhsh_def);
1294
if (iface == NULL || !iface->valid)
1295
goto unlabel_staticlistdef_return;
1296
1297
netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
1298
if (iter_addr4++ < skip_addr4)
1299
continue;
1300
if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1301
iface,
1302
netlbl_unlhsh_addr4_entry(addr4),
1303
NULL,
1304
&cb_arg) < 0) {
1305
iter_addr4--;
1306
goto unlabel_staticlistdef_return;
1307
}
1308
}
1309
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1310
netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
1311
if (iter_addr6++ < skip_addr6)
1312
continue;
1313
if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1314
iface,
1315
NULL,
1316
netlbl_unlhsh_addr6_entry(addr6),
1317
&cb_arg) < 0) {
1318
iter_addr6--;
1319
goto unlabel_staticlistdef_return;
1320
}
1321
}
1322
#endif /* IPv6 */
1323
1324
unlabel_staticlistdef_return:
1325
rcu_read_unlock();
1326
cb->args[0] = skip_addr4;
1327
cb->args[1] = skip_addr6;
1328
return skb->len;
1329
}
1330
1331
/*
1332
* NetLabel Generic NETLINK Command Definitions
1333
*/
1334
1335
static struct genl_ops netlbl_unlabel_genl_ops[] = {
1336
{
1337
.cmd = NLBL_UNLABEL_C_STATICADD,
1338
.flags = GENL_ADMIN_PERM,
1339
.policy = netlbl_unlabel_genl_policy,
1340
.doit = netlbl_unlabel_staticadd,
1341
.dumpit = NULL,
1342
},
1343
{
1344
.cmd = NLBL_UNLABEL_C_STATICREMOVE,
1345
.flags = GENL_ADMIN_PERM,
1346
.policy = netlbl_unlabel_genl_policy,
1347
.doit = netlbl_unlabel_staticremove,
1348
.dumpit = NULL,
1349
},
1350
{
1351
.cmd = NLBL_UNLABEL_C_STATICLIST,
1352
.flags = 0,
1353
.policy = netlbl_unlabel_genl_policy,
1354
.doit = NULL,
1355
.dumpit = netlbl_unlabel_staticlist,
1356
},
1357
{
1358
.cmd = NLBL_UNLABEL_C_STATICADDDEF,
1359
.flags = GENL_ADMIN_PERM,
1360
.policy = netlbl_unlabel_genl_policy,
1361
.doit = netlbl_unlabel_staticadddef,
1362
.dumpit = NULL,
1363
},
1364
{
1365
.cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
1366
.flags = GENL_ADMIN_PERM,
1367
.policy = netlbl_unlabel_genl_policy,
1368
.doit = netlbl_unlabel_staticremovedef,
1369
.dumpit = NULL,
1370
},
1371
{
1372
.cmd = NLBL_UNLABEL_C_STATICLISTDEF,
1373
.flags = 0,
1374
.policy = netlbl_unlabel_genl_policy,
1375
.doit = NULL,
1376
.dumpit = netlbl_unlabel_staticlistdef,
1377
},
1378
{
1379
.cmd = NLBL_UNLABEL_C_ACCEPT,
1380
.flags = GENL_ADMIN_PERM,
1381
.policy = netlbl_unlabel_genl_policy,
1382
.doit = netlbl_unlabel_accept,
1383
.dumpit = NULL,
1384
},
1385
{
1386
.cmd = NLBL_UNLABEL_C_LIST,
1387
.flags = 0,
1388
.policy = netlbl_unlabel_genl_policy,
1389
.doit = netlbl_unlabel_list,
1390
.dumpit = NULL,
1391
},
1392
};
1393
1394
/*
1395
* NetLabel Generic NETLINK Protocol Functions
1396
*/
1397
1398
/**
1399
* netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
1400
*
1401
* Description:
1402
* Register the unlabeled packet NetLabel component with the Generic NETLINK
1403
* mechanism. Returns zero on success, negative values on failure.
1404
*
1405
*/
1406
int __init netlbl_unlabel_genl_init(void)
1407
{
1408
return genl_register_family_with_ops(&netlbl_unlabel_gnl_family,
1409
netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops));
1410
}
1411
1412
/*
1413
* NetLabel KAPI Hooks
1414
*/
1415
1416
static struct notifier_block netlbl_unlhsh_netdev_notifier = {
1417
.notifier_call = netlbl_unlhsh_netdev_handler,
1418
};
1419
1420
/**
1421
* netlbl_unlabel_init - Initialize the unlabeled connection hash table
1422
* @size: the number of bits to use for the hash buckets
1423
*
1424
* Description:
1425
* Initializes the unlabeled connection hash table and registers a network
1426
* device notification handler. This function should only be called by the
1427
* NetLabel subsystem itself during initialization. Returns zero on success,
1428
* non-zero values on error.
1429
*
1430
*/
1431
int __init netlbl_unlabel_init(u32 size)
1432
{
1433
u32 iter;
1434
struct netlbl_unlhsh_tbl *hsh_tbl;
1435
1436
if (size == 0)
1437
return -EINVAL;
1438
1439
hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
1440
if (hsh_tbl == NULL)
1441
return -ENOMEM;
1442
hsh_tbl->size = 1 << size;
1443
hsh_tbl->tbl = kcalloc(hsh_tbl->size,
1444
sizeof(struct list_head),
1445
GFP_KERNEL);
1446
if (hsh_tbl->tbl == NULL) {
1447
kfree(hsh_tbl);
1448
return -ENOMEM;
1449
}
1450
for (iter = 0; iter < hsh_tbl->size; iter++)
1451
INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
1452
1453
rcu_read_lock();
1454
spin_lock(&netlbl_unlhsh_lock);
1455
rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
1456
spin_unlock(&netlbl_unlhsh_lock);
1457
rcu_read_unlock();
1458
1459
register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
1460
1461
return 0;
1462
}
1463
1464
/**
1465
* netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
1466
* @skb: the packet
1467
* @family: protocol family
1468
* @secattr: the security attributes
1469
*
1470
* Description:
1471
* Determine the security attributes, if any, for an unlabled packet and return
1472
* them in @secattr. Returns zero on success and negative values on failure.
1473
*
1474
*/
1475
int netlbl_unlabel_getattr(const struct sk_buff *skb,
1476
u16 family,
1477
struct netlbl_lsm_secattr *secattr)
1478
{
1479
struct netlbl_unlhsh_iface *iface;
1480
1481
rcu_read_lock();
1482
iface = netlbl_unlhsh_search_iface(skb->skb_iif);
1483
if (iface == NULL)
1484
iface = rcu_dereference(netlbl_unlhsh_def);
1485
if (iface == NULL || !iface->valid)
1486
goto unlabel_getattr_nolabel;
1487
switch (family) {
1488
case PF_INET: {
1489
struct iphdr *hdr4;
1490
struct netlbl_af4list *addr4;
1491
1492
hdr4 = ip_hdr(skb);
1493
addr4 = netlbl_af4list_search(hdr4->saddr,
1494
&iface->addr4_list);
1495
if (addr4 == NULL)
1496
goto unlabel_getattr_nolabel;
1497
secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
1498
break;
1499
}
1500
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1501
case PF_INET6: {
1502
struct ipv6hdr *hdr6;
1503
struct netlbl_af6list *addr6;
1504
1505
hdr6 = ipv6_hdr(skb);
1506
addr6 = netlbl_af6list_search(&hdr6->saddr,
1507
&iface->addr6_list);
1508
if (addr6 == NULL)
1509
goto unlabel_getattr_nolabel;
1510
secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
1511
break;
1512
}
1513
#endif /* IPv6 */
1514
default:
1515
goto unlabel_getattr_nolabel;
1516
}
1517
rcu_read_unlock();
1518
1519
secattr->flags |= NETLBL_SECATTR_SECID;
1520
secattr->type = NETLBL_NLTYPE_UNLABELED;
1521
return 0;
1522
1523
unlabel_getattr_nolabel:
1524
rcu_read_unlock();
1525
if (netlabel_unlabel_acceptflg == 0)
1526
return -ENOMSG;
1527
secattr->type = NETLBL_NLTYPE_UNLABELED;
1528
return 0;
1529
}
1530
1531
/**
1532
* netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
1533
*
1534
* Description:
1535
* Set the default NetLabel configuration to allow incoming unlabeled packets
1536
* and to send unlabeled network traffic by default.
1537
*
1538
*/
1539
int __init netlbl_unlabel_defconf(void)
1540
{
1541
int ret_val;
1542
struct netlbl_dom_map *entry;
1543
struct netlbl_audit audit_info;
1544
1545
/* Only the kernel is allowed to call this function and the only time
1546
* it is called is at bootup before the audit subsystem is reporting
1547
* messages so don't worry to much about these values. */
1548
security_task_getsecid(current, &audit_info.secid);
1549
audit_info.loginuid = 0;
1550
audit_info.sessionid = 0;
1551
1552
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1553
if (entry == NULL)
1554
return -ENOMEM;
1555
entry->type = NETLBL_NLTYPE_UNLABELED;
1556
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
1557
if (ret_val != 0)
1558
return ret_val;
1559
1560
netlbl_unlabel_acceptflg_set(1, &audit_info);
1561
1562
return 0;
1563
}
1564
1565