@@ -56,7 +56,8 @@ static DEFINE_SPINLOCK(netlbl_domhsh_lock);
56
56
#define netlbl_domhsh_rcu_deref (p ) \
57
57
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
58
58
static struct netlbl_domhsh_tbl __rcu * netlbl_domhsh ;
59
- static struct netlbl_dom_map __rcu * netlbl_domhsh_def ;
59
+ static struct netlbl_dom_map __rcu * netlbl_domhsh_def_ipv4 ;
60
+ static struct netlbl_dom_map __rcu * netlbl_domhsh_def_ipv6 ;
60
61
61
62
/*
62
63
* Domain Hash Table Helper Functions
@@ -126,18 +127,26 @@ static u32 netlbl_domhsh_hash(const char *key)
126
127
return val & (netlbl_domhsh_rcu_deref (netlbl_domhsh )-> size - 1 );
127
128
}
128
129
130
+ static bool netlbl_family_match (u16 f1 , u16 f2 )
131
+ {
132
+ return (f1 == f2 ) || (f1 == AF_UNSPEC ) || (f2 == AF_UNSPEC );
133
+ }
134
+
129
135
/**
130
136
* netlbl_domhsh_search - Search for a domain entry
131
137
* @domain: the domain
138
+ * @family: the address family
132
139
*
133
140
* Description:
134
141
* Searches the domain hash table and returns a pointer to the hash table
135
- * entry if found, otherwise NULL is returned. The caller is responsible for
142
+ * entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC
143
+ * which matches any address family entries. The caller is responsible for
136
144
* ensuring that the hash table is protected with either a RCU read lock or the
137
145
* hash table lock.
138
146
*
139
147
*/
140
- static struct netlbl_dom_map * netlbl_domhsh_search (const char * domain )
148
+ static struct netlbl_dom_map * netlbl_domhsh_search (const char * domain ,
149
+ u16 family )
141
150
{
142
151
u32 bkt ;
143
152
struct list_head * bkt_list ;
@@ -147,7 +156,9 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
147
156
bkt = netlbl_domhsh_hash (domain );
148
157
bkt_list = & netlbl_domhsh_rcu_deref (netlbl_domhsh )-> tbl [bkt ];
149
158
list_for_each_entry_rcu (iter , bkt_list , list )
150
- if (iter -> valid && strcmp (iter -> domain , domain ) == 0 )
159
+ if (iter -> valid &&
160
+ netlbl_family_match (iter -> family , family ) &&
161
+ strcmp (iter -> domain , domain ) == 0 )
151
162
return iter ;
152
163
}
153
164
@@ -157,28 +168,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
157
168
/**
158
169
* netlbl_domhsh_search_def - Search for a domain entry
159
170
* @domain: the domain
160
- * @def: return default if no match is found
171
+ * @family: the address family
161
172
*
162
173
* Description:
163
174
* Searches the domain hash table and returns a pointer to the hash table
164
175
* entry if an exact match is found, if an exact match is not present in the
165
176
* hash table then the default entry is returned if valid otherwise NULL is
166
- * returned. The caller is responsible ensuring that the hash table is
177
+ * returned. @family may be %AF_UNSPEC which matches any address family
178
+ * entries. The caller is responsible ensuring that the hash table is
167
179
* protected with either a RCU read lock or the hash table lock.
168
180
*
169
181
*/
170
- static struct netlbl_dom_map * netlbl_domhsh_search_def (const char * domain )
182
+ static struct netlbl_dom_map * netlbl_domhsh_search_def (const char * domain ,
183
+ u16 family )
171
184
{
172
185
struct netlbl_dom_map * entry ;
173
186
174
- entry = netlbl_domhsh_search (domain );
175
- if (entry == NULL ) {
176
- entry = netlbl_domhsh_rcu_deref (netlbl_domhsh_def );
177
- if (entry != NULL && !entry -> valid )
178
- entry = NULL ;
187
+ entry = netlbl_domhsh_search (domain , family );
188
+ if (entry != NULL )
189
+ return entry ;
190
+ if (family == AF_INET || family == AF_UNSPEC ) {
191
+ entry = netlbl_domhsh_rcu_deref (netlbl_domhsh_def_ipv4 );
192
+ if (entry != NULL && entry -> valid )
193
+ return entry ;
194
+ }
195
+ if (family == AF_INET6 || family == AF_UNSPEC ) {
196
+ entry = netlbl_domhsh_rcu_deref (netlbl_domhsh_def_ipv6 );
197
+ if (entry != NULL && entry -> valid )
198
+ return entry ;
179
199
}
180
200
181
- return entry ;
201
+ return NULL ;
182
202
}
183
203
184
204
/**
@@ -264,13 +284,19 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
264
284
if (entry == NULL )
265
285
return - EINVAL ;
266
286
287
+ if (entry -> family != AF_INET && entry -> family != AF_INET6 &&
288
+ (entry -> family != AF_UNSPEC ||
289
+ entry -> def .type != NETLBL_NLTYPE_UNLABELED ))
290
+ return - EINVAL ;
291
+
267
292
switch (entry -> def .type ) {
268
293
case NETLBL_NLTYPE_UNLABELED :
269
294
if (entry -> def .cipso != NULL || entry -> def .addrsel != NULL )
270
295
return - EINVAL ;
271
296
break ;
272
297
case NETLBL_NLTYPE_CIPSOV4 :
273
- if (entry -> def .cipso == NULL )
298
+ if (entry -> family != AF_INET ||
299
+ entry -> def .cipso == NULL )
274
300
return - EINVAL ;
275
301
break ;
276
302
case NETLBL_NLTYPE_ADDRSELECT :
@@ -358,15 +384,18 @@ int __init netlbl_domhsh_init(u32 size)
358
384
*
359
385
* Description:
360
386
* Adds a new entry to the domain hash table and handles any updates to the
361
- * lower level protocol handler (i.e. CIPSO). Returns zero on success,
362
- * negative on failure.
387
+ * lower level protocol handler (i.e. CIPSO). @entry->family may be set to
388
+ * %AF_UNSPEC which will add an entry that matches all address families. This
389
+ * is only useful for the unlabelled type and will only succeed if there is no
390
+ * existing entry for any address family with the same domain. Returns zero
391
+ * on success, negative on failure.
363
392
*
364
393
*/
365
394
int netlbl_domhsh_add (struct netlbl_dom_map * entry ,
366
395
struct netlbl_audit * audit_info )
367
396
{
368
397
int ret_val = 0 ;
369
- struct netlbl_dom_map * entry_old ;
398
+ struct netlbl_dom_map * entry_old , * entry_b ;
370
399
struct netlbl_af4list * iter4 ;
371
400
struct netlbl_af4list * tmp4 ;
372
401
#if IS_ENABLED (CONFIG_IPV6 )
@@ -385,9 +414,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
385
414
rcu_read_lock ();
386
415
spin_lock (& netlbl_domhsh_lock );
387
416
if (entry -> domain != NULL )
388
- entry_old = netlbl_domhsh_search (entry -> domain );
417
+ entry_old = netlbl_domhsh_search (entry -> domain , entry -> family );
389
418
else
390
- entry_old = netlbl_domhsh_search_def (entry -> domain );
419
+ entry_old = netlbl_domhsh_search_def (entry -> domain ,
420
+ entry -> family );
391
421
if (entry_old == NULL ) {
392
422
entry -> valid = 1 ;
393
423
@@ -397,7 +427,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
397
427
& rcu_dereference (netlbl_domhsh )-> tbl [bkt ]);
398
428
} else {
399
429
INIT_LIST_HEAD (& entry -> list );
400
- rcu_assign_pointer (netlbl_domhsh_def , entry );
430
+ switch (entry -> family ) {
431
+ case AF_INET :
432
+ rcu_assign_pointer (netlbl_domhsh_def_ipv4 ,
433
+ entry );
434
+ break ;
435
+ case AF_INET6 :
436
+ rcu_assign_pointer (netlbl_domhsh_def_ipv6 ,
437
+ entry );
438
+ break ;
439
+ case AF_UNSPEC :
440
+ if (entry -> def .type !=
441
+ NETLBL_NLTYPE_UNLABELED ) {
442
+ ret_val = - EINVAL ;
443
+ goto add_return ;
444
+ }
445
+ entry_b = kzalloc (sizeof (* entry_b ), GFP_ATOMIC );
446
+ if (entry_b == NULL ) {
447
+ ret_val = - ENOMEM ;
448
+ goto add_return ;
449
+ }
450
+ entry_b -> family = AF_INET6 ;
451
+ entry_b -> def .type = NETLBL_NLTYPE_UNLABELED ;
452
+ entry_b -> valid = 1 ;
453
+ entry -> family = AF_INET ;
454
+ rcu_assign_pointer (netlbl_domhsh_def_ipv4 ,
455
+ entry );
456
+ rcu_assign_pointer (netlbl_domhsh_def_ipv6 ,
457
+ entry_b );
458
+ break ;
459
+ default :
460
+ /* Already checked in
461
+ * netlbl_domhsh_validate(). */
462
+ ret_val = - EINVAL ;
463
+ goto add_return ;
464
+ }
401
465
}
402
466
403
467
if (entry -> def .type == NETLBL_NLTYPE_ADDRSELECT ) {
@@ -513,10 +577,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
513
577
spin_lock (& netlbl_domhsh_lock );
514
578
if (entry -> valid ) {
515
579
entry -> valid = 0 ;
516
- if (entry != rcu_dereference (netlbl_domhsh_def ))
517
- list_del_rcu (& entry -> list );
580
+ if (entry == rcu_dereference (netlbl_domhsh_def_ipv4 ))
581
+ RCU_INIT_POINTER (netlbl_domhsh_def_ipv4 , NULL );
582
+ else if (entry == rcu_dereference (netlbl_domhsh_def_ipv6 ))
583
+ RCU_INIT_POINTER (netlbl_domhsh_def_ipv6 , NULL );
518
584
else
519
- RCU_INIT_POINTER ( netlbl_domhsh_def , NULL );
585
+ list_del_rcu ( & entry -> list );
520
586
} else
521
587
ret_val = - ENOENT ;
522
588
spin_unlock (& netlbl_domhsh_lock );
@@ -583,9 +649,9 @@ int netlbl_domhsh_remove_af4(const char *domain,
583
649
rcu_read_lock ();
584
650
585
651
if (domain )
586
- entry_map = netlbl_domhsh_search (domain );
652
+ entry_map = netlbl_domhsh_search (domain , AF_INET );
587
653
else
588
- entry_map = netlbl_domhsh_search_def (domain );
654
+ entry_map = netlbl_domhsh_search_def (domain , AF_INET );
589
655
if (entry_map == NULL ||
590
656
entry_map -> def .type != NETLBL_NLTYPE_ADDRSELECT )
591
657
goto remove_af4_failure ;
@@ -625,58 +691,84 @@ int netlbl_domhsh_remove_af4(const char *domain,
625
691
/**
626
692
* netlbl_domhsh_remove - Removes an entry from the domain hash table
627
693
* @domain: the domain to remove
694
+ * @family: address family
628
695
* @audit_info: NetLabel audit information
629
696
*
630
697
* Description:
631
698
* Removes an entry from the domain hash table and handles any updates to the
632
- * lower level protocol handler (i.e. CIPSO). Returns zero on success,
633
- * negative on failure.
699
+ * lower level protocol handler (i.e. CIPSO). @family may be %AF_UNSPEC which
700
+ * removes all address family entries. Returns zero on success, negative on
701
+ * failure.
634
702
*
635
703
*/
636
- int netlbl_domhsh_remove (const char * domain , struct netlbl_audit * audit_info )
704
+ int netlbl_domhsh_remove (const char * domain , u16 family ,
705
+ struct netlbl_audit * audit_info )
637
706
{
638
- int ret_val ;
707
+ int ret_val = - EINVAL ;
639
708
struct netlbl_dom_map * entry ;
640
709
641
710
rcu_read_lock ();
642
- if (domain )
643
- entry = netlbl_domhsh_search (domain );
644
- else
645
- entry = netlbl_domhsh_search_def (domain );
646
- ret_val = netlbl_domhsh_remove_entry (entry , audit_info );
711
+
712
+ if (family == AF_INET || family == AF_UNSPEC ) {
713
+ if (domain )
714
+ entry = netlbl_domhsh_search (domain , AF_INET );
715
+ else
716
+ entry = netlbl_domhsh_search_def (domain , AF_INET );
717
+ ret_val = netlbl_domhsh_remove_entry (entry , audit_info );
718
+ if (ret_val && ret_val != - ENOENT )
719
+ goto done ;
720
+ }
721
+ if (family == AF_INET6 || family == AF_UNSPEC ) {
722
+ int ret_val2 ;
723
+
724
+ if (domain )
725
+ entry = netlbl_domhsh_search (domain , AF_INET6 );
726
+ else
727
+ entry = netlbl_domhsh_search_def (domain , AF_INET6 );
728
+ ret_val2 = netlbl_domhsh_remove_entry (entry , audit_info );
729
+ if (ret_val2 != - ENOENT )
730
+ ret_val = ret_val2 ;
731
+ }
732
+ done :
647
733
rcu_read_unlock ();
648
734
649
735
return ret_val ;
650
736
}
651
737
652
738
/**
653
739
* netlbl_domhsh_remove_default - Removes the default entry from the table
740
+ * @family: address family
654
741
* @audit_info: NetLabel audit information
655
742
*
656
743
* Description:
657
- * Removes/resets the default entry for the domain hash table and handles any
658
- * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
659
- * success, non-zero on failure.
744
+ * Removes/resets the default entry corresponding to @family from the domain
745
+ * hash table and handles any updates to the lower level protocol handler
746
+ * (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family
747
+ * entries. Returns zero on success, negative on failure.
660
748
*
661
749
*/
662
- int netlbl_domhsh_remove_default (struct netlbl_audit * audit_info )
750
+ int netlbl_domhsh_remove_default (u16 family , struct netlbl_audit * audit_info )
663
751
{
664
- return netlbl_domhsh_remove (NULL , audit_info );
752
+ return netlbl_domhsh_remove (NULL , family , audit_info );
665
753
}
666
754
667
755
/**
668
756
* netlbl_domhsh_getentry - Get an entry from the domain hash table
669
757
* @domain: the domain name to search for
758
+ * @family: address family
670
759
*
671
760
* Description:
672
761
* Look through the domain hash table searching for an entry to match @domain,
673
- * return a pointer to a copy of the entry or NULL. The caller is responsible
674
- * for ensuring that rcu_read_[un]lock() is called.
762
+ * with address family @family, return a pointer to a copy of the entry or
763
+ * NULL. The caller is responsible for ensuring that rcu_read_[un]lock() is
764
+ * called.
675
765
*
676
766
*/
677
- struct netlbl_dom_map * netlbl_domhsh_getentry (const char * domain )
767
+ struct netlbl_dom_map * netlbl_domhsh_getentry (const char * domain , u16 family )
678
768
{
679
- return netlbl_domhsh_search_def (domain );
769
+ if (family == AF_UNSPEC )
770
+ return NULL ;
771
+ return netlbl_domhsh_search_def (domain , family );
680
772
}
681
773
682
774
/**
@@ -696,7 +788,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
696
788
struct netlbl_dom_map * dom_iter ;
697
789
struct netlbl_af4list * addr_iter ;
698
790
699
- dom_iter = netlbl_domhsh_search_def (domain );
791
+ dom_iter = netlbl_domhsh_search_def (domain , AF_INET );
700
792
if (dom_iter == NULL )
701
793
return NULL ;
702
794
@@ -726,7 +818,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
726
818
struct netlbl_dom_map * dom_iter ;
727
819
struct netlbl_af6list * addr_iter ;
728
820
729
- dom_iter = netlbl_domhsh_search_def (domain );
821
+ dom_iter = netlbl_domhsh_search_def (domain , AF_INET6 );
730
822
if (dom_iter == NULL )
731
823
return NULL ;
732
824
0 commit comments