Blame view

net/netlabel/netlabel_domainhash.c 20.7 KB
d15c345fe   Paul Moore   [NetLabel]: core ...
1
2
3
4
5
6
7
8
  /*
   * NetLabel Domain Hash Table
   *
   * This file manages the domain hash table that NetLabel uses to determine
   * which network labeling protocol to use for a given domain.  The NetLabel
   * system manages static and dynamic label mappings for network protocols such
   * as CIPSO and RIPSO.
   *
82c21bfab   Paul Moore   doc: Update the e...
9
   * Author: Paul Moore <paul@paul-moore.com>
d15c345fe   Paul Moore   [NetLabel]: core ...
10
11
12
13
   *
   */
  
  /*
63c416887   Paul Moore   netlabel: Add net...
14
   * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
d15c345fe   Paul Moore   [NetLabel]: core ...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   *
   * This program is free software;  you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY;  without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   * the GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program;  if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   *
   */
  
  #include <linux/types.h>
82524746c   Franck Bui-Huu   rcu: split list.h...
33
  #include <linux/rculist.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
34
35
36
  #include <linux/skbuff.h>
  #include <linux/spinlock.h>
  #include <linux/string.h>
32f50cdee   Paul Moore   [NetLabel]: add a...
37
  #include <linux/audit.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
38
  #include <linux/slab.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
39
40
41
42
43
  #include <net/netlabel.h>
  #include <net/cipso_ipv4.h>
  #include <asm/bug.h>
  
  #include "netlabel_mgmt.h"
63c416887   Paul Moore   netlabel: Add net...
44
  #include "netlabel_addrlist.h"
d15c345fe   Paul Moore   [NetLabel]: core ...
45
  #include "netlabel_domainhash.h"
32f50cdee   Paul Moore   [NetLabel]: add a...
46
  #include "netlabel_user.h"
d15c345fe   Paul Moore   [NetLabel]: core ...
47
48
49
50
51
52
53
  
  struct netlbl_domhsh_tbl {
  	struct list_head *tbl;
  	u32 size;
  };
  
  /* Domain hash table */
b914f3a2a   Paul Moore   netlabel: Fix sev...
54
55
  /* updates should be so rare that having one spinlock for the entire hash table
   * should be okay */
8ce11e6a9   Adrian Bunk   [NET]: Make code ...
56
  static DEFINE_SPINLOCK(netlbl_domhsh_lock);
b914f3a2a   Paul Moore   netlabel: Fix sev...
57
  #define netlbl_domhsh_rcu_deref(p) \
d8bf4ca9c   Michal Hocko   rcu: treewide: Do...
58
  	rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
d15c345fe   Paul Moore   [NetLabel]: core ...
59
  static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
d15c345fe   Paul Moore   [NetLabel]: core ...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
  
  /*
   * Domain Hash Table Helper Functions
   */
  
  /**
   * netlbl_domhsh_free_entry - Frees a domain hash table entry
   * @entry: the entry's RCU field
   *
   * Description:
   * This function is designed to be used as a callback to the call_rcu()
   * function so that the memory allocated to a hash table entry can be released
   * safely.
   *
   */
  static void netlbl_domhsh_free_entry(struct rcu_head *entry)
  {
  	struct netlbl_dom_map *ptr;
63c416887   Paul Moore   netlabel: Add net...
79
80
  	struct netlbl_af4list *iter4;
  	struct netlbl_af4list *tmp4;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
81
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
82
83
84
  	struct netlbl_af6list *iter6;
  	struct netlbl_af6list *tmp6;
  #endif /* IPv6 */
d15c345fe   Paul Moore   [NetLabel]: core ...
85
86
  
  	ptr = container_of(entry, struct netlbl_dom_map, rcu);
63c416887   Paul Moore   netlabel: Add net...
87
88
89
90
91
92
  	if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
  		netlbl_af4list_foreach_safe(iter4, tmp4,
  					    &ptr->type_def.addrsel->list4) {
  			netlbl_af4list_remove_entry(iter4);
  			kfree(netlbl_domhsh_addr4_entry(iter4));
  		}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
93
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
94
95
96
97
98
99
100
  		netlbl_af6list_foreach_safe(iter6, tmp6,
  					    &ptr->type_def.addrsel->list6) {
  			netlbl_af6list_remove_entry(iter6);
  			kfree(netlbl_domhsh_addr6_entry(iter6));
  		}
  #endif /* IPv6 */
  	}
d15c345fe   Paul Moore   [NetLabel]: core ...
101
102
103
104
105
106
107
108
109
110
  	kfree(ptr->domain);
  	kfree(ptr);
  }
  
  /**
   * netlbl_domhsh_hash - Hashing function for the domain hash table
   * @domain: the domain name to hash
   *
   * Description:
   * This is the hashing function for the domain hash table, it returns the
25985edce   Lucas De Marchi   Fix common misspe...
111
   * correct bucket number for the domain.  The caller is responsible for
b914f3a2a   Paul Moore   netlabel: Fix sev...
112
113
   * ensuring that the hash table is protected with either a RCU read lock or the
   * hash table lock.
d15c345fe   Paul Moore   [NetLabel]: core ...
114
115
116
117
118
119
120
121
122
123
124
125
126
   *
   */
  static u32 netlbl_domhsh_hash(const char *key)
  {
  	u32 iter;
  	u32 val;
  	u32 len;
  
  	/* This is taken (with slight modification) from
  	 * security/selinux/ss/symtab.c:symhash() */
  
  	for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
  		val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
b914f3a2a   Paul Moore   netlabel: Fix sev...
127
  	return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
d15c345fe   Paul Moore   [NetLabel]: core ...
128
129
130
131
132
  }
  
  /**
   * netlbl_domhsh_search - Search for a domain entry
   * @domain: the domain
d15c345fe   Paul Moore   [NetLabel]: core ...
133
134
135
   *
   * Description:
   * Searches the domain hash table and returns a pointer to the hash table
25985edce   Lucas De Marchi   Fix common misspe...
136
   * entry if found, otherwise NULL is returned.  The caller is responsible for
b914f3a2a   Paul Moore   netlabel: Fix sev...
137
138
   * ensuring that the hash table is protected with either a RCU read lock or the
   * hash table lock.
d15c345fe   Paul Moore   [NetLabel]: core ...
139
140
   *
   */
b64397e0b   Paul Moore   NetLabel: Cleanup...
141
  static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
d15c345fe   Paul Moore   [NetLabel]: core ...
142
143
  {
  	u32 bkt;
561967010   Paul Moore   netlabel: Fix som...
144
  	struct list_head *bkt_list;
d15c345fe   Paul Moore   [NetLabel]: core ...
145
146
147
148
  	struct netlbl_dom_map *iter;
  
  	if (domain != NULL) {
  		bkt = netlbl_domhsh_hash(domain);
b914f3a2a   Paul Moore   netlabel: Fix sev...
149
  		bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
561967010   Paul Moore   netlabel: Fix som...
150
  		list_for_each_entry_rcu(iter, bkt_list, list)
d15c345fe   Paul Moore   [NetLabel]: core ...
151
152
153
  			if (iter->valid && strcmp(iter->domain, domain) == 0)
  				return iter;
  	}
b64397e0b   Paul Moore   NetLabel: Cleanup...
154
155
156
157
158
159
160
161
162
163
164
165
  	return NULL;
  }
  
  /**
   * netlbl_domhsh_search_def - Search for a domain entry
   * @domain: the domain
   * @def: return default if no match is found
   *
   * Description:
   * Searches the domain hash table and returns a pointer to the hash table
   * entry if an exact match is found, if an exact match is not present in the
   * hash table then the default entry is returned if valid otherwise NULL is
25985edce   Lucas De Marchi   Fix common misspe...
166
   * returned.  The caller is responsible ensuring that the hash table is
b914f3a2a   Paul Moore   netlabel: Fix sev...
167
   * protected with either a RCU read lock or the hash table lock.
b64397e0b   Paul Moore   NetLabel: Cleanup...
168
169
170
171
172
173
174
175
   *
   */
  static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
  {
  	struct netlbl_dom_map *entry;
  
  	entry = netlbl_domhsh_search(domain);
  	if (entry == NULL) {
b914f3a2a   Paul Moore   netlabel: Fix sev...
176
  		entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
4c3a0a254   Pavel Emelyanov   [NETLABEL]: Fix l...
177
178
  		if (entry != NULL && !entry->valid)
  			entry = NULL;
d15c345fe   Paul Moore   [NetLabel]: core ...
179
  	}
4c3a0a254   Pavel Emelyanov   [NETLABEL]: Fix l...
180
  	return entry;
d15c345fe   Paul Moore   [NetLabel]: core ...
181
  }
63c416887   Paul Moore   netlabel: Add net...
182
183
184
185
186
187
188
189
190
191
  /**
   * netlbl_domhsh_audit_add - Generate an audit entry for an add event
   * @entry: the entry being added
   * @addr4: the IPv4 address information
   * @addr6: the IPv6 address information
   * @result: the result code
   * @audit_info: NetLabel audit information
   *
   * Description:
   * Generate an audit record for adding a new NetLabel/LSM mapping entry with
25985edce   Lucas De Marchi   Fix common misspe...
192
   * the given information.  Caller is responsible for holding the necessary
63c416887   Paul Moore   netlabel: Add net...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
   * locks.
   *
   */
  static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
  				    struct netlbl_af4list *addr4,
  				    struct netlbl_af6list *addr6,
  				    int result,
  				    struct netlbl_audit *audit_info)
  {
  	struct audit_buffer *audit_buf;
  	struct cipso_v4_doi *cipsov4 = NULL;
  	u32 type;
  
  	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
  	if (audit_buf != NULL) {
  		audit_log_format(audit_buf, " nlbl_domain=%s",
  				 entry->domain ? entry->domain : "(default)");
  		if (addr4 != NULL) {
  			struct netlbl_domaddr4_map *map4;
  			map4 = netlbl_domhsh_addr4_entry(addr4);
  			type = map4->type;
  			cipsov4 = map4->type_def.cipsov4;
  			netlbl_af4list_audit_addr(audit_buf, 0, NULL,
  						  addr4->addr, addr4->mask);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
217
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  		} else if (addr6 != NULL) {
  			struct netlbl_domaddr6_map *map6;
  			map6 = netlbl_domhsh_addr6_entry(addr6);
  			type = map6->type;
  			netlbl_af6list_audit_addr(audit_buf, 0, NULL,
  						  &addr6->addr, &addr6->mask);
  #endif /* IPv6 */
  		} else {
  			type = entry->type;
  			cipsov4 = entry->type_def.cipsov4;
  		}
  		switch (type) {
  		case NETLBL_NLTYPE_UNLABELED:
  			audit_log_format(audit_buf, " nlbl_protocol=unlbl");
  			break;
  		case NETLBL_NLTYPE_CIPSOV4:
  			BUG_ON(cipsov4 == NULL);
  			audit_log_format(audit_buf,
  					 " nlbl_protocol=cipsov4 cipso_doi=%u",
  					 cipsov4->doi);
  			break;
  		}
  		audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
  		audit_log_end(audit_buf);
  	}
  }
d15c345fe   Paul Moore   [NetLabel]: core ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  /*
   * Domain Hash Table Functions
   */
  
  /**
   * netlbl_domhsh_init - Init for the domain hash
   * @size: the number of bits to use for the hash buckets
   *
   * Description:
   * Initializes the domain hash table, should be called only by
   * netlbl_user_init() during initialization.  Returns zero on success, non-zero
   * values on error.
   *
   */
05705e4e1   Pavel Emelyanov   [NETLABEL]: Move ...
258
  int __init netlbl_domhsh_init(u32 size)
d15c345fe   Paul Moore   [NetLabel]: core ...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  {
  	u32 iter;
  	struct netlbl_domhsh_tbl *hsh_tbl;
  
  	if (size == 0)
  		return -EINVAL;
  
  	hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
  	if (hsh_tbl == NULL)
  		return -ENOMEM;
  	hsh_tbl->size = 1 << size;
  	hsh_tbl->tbl = kcalloc(hsh_tbl->size,
  			       sizeof(struct list_head),
  			       GFP_KERNEL);
  	if (hsh_tbl->tbl == NULL) {
  		kfree(hsh_tbl);
  		return -ENOMEM;
  	}
  	for (iter = 0; iter < hsh_tbl->size; iter++)
  		INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
d15c345fe   Paul Moore   [NetLabel]: core ...
279
  	spin_lock(&netlbl_domhsh_lock);
cf778b00e   Eric Dumazet   net: reintroduce ...
280
  	rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
d15c345fe   Paul Moore   [NetLabel]: core ...
281
  	spin_unlock(&netlbl_domhsh_lock);
d15c345fe   Paul Moore   [NetLabel]: core ...
282
283
284
285
286
287
288
  
  	return 0;
  }
  
  /**
   * netlbl_domhsh_add - Adds a entry to the domain hash table
   * @entry: the entry to add
95d4e6be2   Paul Moore   [NetLabel]: audit...
289
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
290
291
292
293
294
295
296
   *
   * Description:
   * Adds a new entry to the domain hash table and handles any updates to the
   * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
   * negative on failure.
   *
   */
95d4e6be2   Paul Moore   [NetLabel]: audit...
297
298
  int netlbl_domhsh_add(struct netlbl_dom_map *entry,
  		      struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
299
  {
63c416887   Paul Moore   netlabel: Add net...
300
301
302
303
  	int ret_val = 0;
  	struct netlbl_dom_map *entry_old;
  	struct netlbl_af4list *iter4;
  	struct netlbl_af4list *tmp4;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
304
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
305
306
307
  	struct netlbl_af6list *iter6;
  	struct netlbl_af6list *tmp6;
  #endif /* IPv6 */
d15c345fe   Paul Moore   [NetLabel]: core ...
308

b914f3a2a   Paul Moore   netlabel: Fix sev...
309
310
311
312
  	/* XXX - we can remove this RCU read lock as the spinlock protects the
  	 *       entire function, but before we do we need to fixup the
  	 *       netlbl_af[4,6]list RCU functions to do "the right thing" with
  	 *       respect to rcu_dereference() when only a spinlock is held. */
d15c345fe   Paul Moore   [NetLabel]: core ...
313
  	rcu_read_lock();
1c3fad936   Paul Moore   NetLabel: Consoli...
314
  	spin_lock(&netlbl_domhsh_lock);
63c416887   Paul Moore   netlabel: Add net...
315
316
317
318
319
320
  	if (entry->domain != NULL)
  		entry_old = netlbl_domhsh_search(entry->domain);
  	else
  		entry_old = netlbl_domhsh_search_def(entry->domain);
  	if (entry_old == NULL) {
  		entry->valid = 1;
63c416887   Paul Moore   netlabel: Add net...
321
322
323
  
  		if (entry->domain != NULL) {
  			u32 bkt = netlbl_domhsh_hash(entry->domain);
d15c345fe   Paul Moore   [NetLabel]: core ...
324
  			list_add_tail_rcu(&entry->list,
3482fd909   Paul Moore   [NetLabel]: add m...
325
  				    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
63c416887   Paul Moore   netlabel: Add net...
326
327
  		} else {
  			INIT_LIST_HEAD(&entry->list);
cf778b00e   Eric Dumazet   net: reintroduce ...
328
  			rcu_assign_pointer(netlbl_domhsh_def, entry);
de64688ff   Paul Moore   NetLabel: honor t...
329
  		}
d15c345fe   Paul Moore   [NetLabel]: core ...
330

63c416887   Paul Moore   netlabel: Add net...
331
332
333
334
335
  		if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
  			netlbl_af4list_foreach_rcu(iter4,
  					       &entry->type_def.addrsel->list4)
  				netlbl_domhsh_audit_add(entry, iter4, NULL,
  							ret_val, audit_info);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
336
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  			netlbl_af6list_foreach_rcu(iter6,
  					       &entry->type_def.addrsel->list6)
  				netlbl_domhsh_audit_add(entry, NULL, iter6,
  							ret_val, audit_info);
  #endif /* IPv6 */
  		} else
  			netlbl_domhsh_audit_add(entry, NULL, NULL,
  						ret_val, audit_info);
  	} else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
  		   entry->type == NETLBL_NLTYPE_ADDRSELECT) {
  		struct list_head *old_list4;
  		struct list_head *old_list6;
  
  		old_list4 = &entry_old->type_def.addrsel->list4;
  		old_list6 = &entry_old->type_def.addrsel->list6;
  
  		/* we only allow the addition of address selectors if all of
  		 * the selectors do not exist in the existing domain map */
  		netlbl_af4list_foreach_rcu(iter4,
  					   &entry->type_def.addrsel->list4)
  			if (netlbl_af4list_search_exact(iter4->addr,
  							iter4->mask,
  							old_list4)) {
  				ret_val = -EEXIST;
  				goto add_return;
  			}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
363
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  		netlbl_af6list_foreach_rcu(iter6,
  					   &entry->type_def.addrsel->list6)
  			if (netlbl_af6list_search_exact(&iter6->addr,
  							&iter6->mask,
  							old_list6)) {
  				ret_val = -EEXIST;
  				goto add_return;
  			}
  #endif /* IPv6 */
  
  		netlbl_af4list_foreach_safe(iter4, tmp4,
  					    &entry->type_def.addrsel->list4) {
  			netlbl_af4list_remove_entry(iter4);
  			iter4->valid = 1;
  			ret_val = netlbl_af4list_add(iter4, old_list4);
  			netlbl_domhsh_audit_add(entry_old, iter4, NULL,
  						ret_val, audit_info);
  			if (ret_val != 0)
  				goto add_return;
  		}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
384
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  		netlbl_af6list_foreach_safe(iter6, tmp6,
  					    &entry->type_def.addrsel->list6) {
  			netlbl_af6list_remove_entry(iter6);
  			iter6->valid = 1;
  			ret_val = netlbl_af6list_add(iter6, old_list6);
  			netlbl_domhsh_audit_add(entry_old, NULL, iter6,
  						ret_val, audit_info);
  			if (ret_val != 0)
  				goto add_return;
  		}
  #endif /* IPv6 */
  	} else
  		ret_val = -EINVAL;
  
  add_return:
  	spin_unlock(&netlbl_domhsh_lock);
  	rcu_read_unlock();
d15c345fe   Paul Moore   [NetLabel]: core ...
402
403
404
405
406
407
  	return ret_val;
  }
  
  /**
   * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
   * @entry: the entry to add
95d4e6be2   Paul Moore   [NetLabel]: audit...
408
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
409
410
411
412
413
414
415
   *
   * Description:
   * Adds a new default entry to the domain hash table and handles any updates
   * to the lower level protocol handler (i.e. CIPSO).  Returns zero on success,
   * negative on failure.
   *
   */
95d4e6be2   Paul Moore   [NetLabel]: audit...
416
417
  int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
  			      struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
418
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
419
  	return netlbl_domhsh_add(entry, audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
420
421
422
  }
  
  /**
b1edeb102   Paul Moore   netlabel: Replace...
423
424
   * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
   * @entry: the entry to remove
95d4e6be2   Paul Moore   [NetLabel]: audit...
425
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
426
427
428
   *
   * Description:
   * Removes an entry from the domain hash table and handles any updates to the
b1edeb102   Paul Moore   netlabel: Replace...
429
430
431
   * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
   * ensuring that the RCU read lock is held.  Returns zero on success, negative
   * on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
432
433
   *
   */
b1edeb102   Paul Moore   netlabel: Replace...
434
435
  int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
  			       struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
436
  {
b1edeb102   Paul Moore   netlabel: Replace...
437
  	int ret_val = 0;
32f50cdee   Paul Moore   [NetLabel]: add a...
438
  	struct audit_buffer *audit_buf;
d15c345fe   Paul Moore   [NetLabel]: core ...
439

d15c345fe   Paul Moore   [NetLabel]: core ...
440
  	if (entry == NULL)
b1edeb102   Paul Moore   netlabel: Replace...
441
  		return -ENOENT;
1c3fad936   Paul Moore   NetLabel: Consoli...
442
443
444
445
  	spin_lock(&netlbl_domhsh_lock);
  	if (entry->valid) {
  		entry->valid = 0;
  		if (entry != rcu_dereference(netlbl_domhsh_def))
d15c345fe   Paul Moore   [NetLabel]: core ...
446
  			list_del_rcu(&entry->list);
1c3fad936   Paul Moore   NetLabel: Consoli...
447
  		else
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
448
  			RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
b1edeb102   Paul Moore   netlabel: Replace...
449
450
  	} else
  		ret_val = -ENOENT;
1c3fad936   Paul Moore   NetLabel: Consoli...
451
  	spin_unlock(&netlbl_domhsh_lock);
32f50cdee   Paul Moore   [NetLabel]: add a...
452

95d4e6be2   Paul Moore   [NetLabel]: audit...
453
  	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
de64688ff   Paul Moore   NetLabel: honor t...
454
455
456
457
458
459
460
  	if (audit_buf != NULL) {
  		audit_log_format(audit_buf,
  				 " nlbl_domain=%s res=%u",
  				 entry->domain ? entry->domain : "(default)",
  				 ret_val == 0 ? 1 : 0);
  		audit_log_end(audit_buf);
  	}
95d4e6be2   Paul Moore   [NetLabel]: audit...
461

b1edeb102   Paul Moore   netlabel: Replace...
462
  	if (ret_val == 0) {
63c416887   Paul Moore   netlabel: Add net...
463
464
  		struct netlbl_af4list *iter4;
  		struct netlbl_domaddr4_map *map4;
b1edeb102   Paul Moore   netlabel: Replace...
465
  		switch (entry->type) {
63c416887   Paul Moore   netlabel: Add net...
466
467
468
469
470
471
472
473
474
  		case NETLBL_NLTYPE_ADDRSELECT:
  			netlbl_af4list_foreach_rcu(iter4,
  					     &entry->type_def.addrsel->list4) {
  				map4 = netlbl_domhsh_addr4_entry(iter4);
  				cipso_v4_doi_putdef(map4->type_def.cipsov4);
  			}
  			/* no need to check the IPv6 list since we currently
  			 * support only unlabeled protocols for IPv6 */
  			break;
b1edeb102   Paul Moore   netlabel: Replace...
475
476
477
478
  		case NETLBL_NLTYPE_CIPSOV4:
  			cipso_v4_doi_putdef(entry->type_def.cipsov4);
  			break;
  		}
4be2700fb   Paul Moore   [NetLabel]: corre...
479
  		call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
b1edeb102   Paul Moore   netlabel: Replace...
480
481
482
483
484
485
  	}
  
  	return ret_val;
  }
  
  /**
6c2e8ac09   Paul Moore   netlabel: Update ...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
   * netlbl_domhsh_remove_af4 - Removes an address selector entry
   * @domain: the domain
   * @addr: IPv4 address
   * @mask: IPv4 address mask
   * @audit_info: NetLabel audit information
   *
   * Description:
   * Removes an individual address selector from a domain mapping and potentially
   * the entire mapping if it is empty.  Returns zero on success, negative values
   * on failure.
   *
   */
  int netlbl_domhsh_remove_af4(const char *domain,
  			     const struct in_addr *addr,
  			     const struct in_addr *mask,
  			     struct netlbl_audit *audit_info)
  {
  	struct netlbl_dom_map *entry_map;
  	struct netlbl_af4list *entry_addr;
  	struct netlbl_af4list *iter4;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
506
  #if IS_ENABLED(CONFIG_IPV6)
6c2e8ac09   Paul Moore   netlabel: Update ...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
  	struct netlbl_af6list *iter6;
  #endif /* IPv6 */
  	struct netlbl_domaddr4_map *entry;
  
  	rcu_read_lock();
  
  	if (domain)
  		entry_map = netlbl_domhsh_search(domain);
  	else
  		entry_map = netlbl_domhsh_search_def(domain);
  	if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
  		goto remove_af4_failure;
  
  	spin_lock(&netlbl_domhsh_lock);
  	entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
  					   &entry_map->type_def.addrsel->list4);
  	spin_unlock(&netlbl_domhsh_lock);
  
  	if (entry_addr == NULL)
  		goto remove_af4_failure;
  	netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
  		goto remove_af4_single_addr;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
529
  #if IS_ENABLED(CONFIG_IPV6)
6c2e8ac09   Paul Moore   netlabel: Update ...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  	netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
  		goto remove_af4_single_addr;
  #endif /* IPv6 */
  	/* the domain mapping is empty so remove it from the mapping table */
  	netlbl_domhsh_remove_entry(entry_map, audit_info);
  
  remove_af4_single_addr:
  	rcu_read_unlock();
  	/* yick, we can't use call_rcu here because we don't have a rcu head
  	 * pointer but hopefully this should be a rare case so the pause
  	 * shouldn't be a problem */
  	synchronize_rcu();
  	entry = netlbl_domhsh_addr4_entry(entry_addr);
  	cipso_v4_doi_putdef(entry->type_def.cipsov4);
  	kfree(entry);
  	return 0;
  
  remove_af4_failure:
  	rcu_read_unlock();
  	return -ENOENT;
  }
  
  /**
b1edeb102   Paul Moore   netlabel: Replace...
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
   * netlbl_domhsh_remove - Removes an entry from the domain hash table
   * @domain: the domain to remove
   * @audit_info: NetLabel audit information
   *
   * Description:
   * Removes an entry from the domain hash table and handles any updates to the
   * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
   * negative on failure.
   *
   */
  int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
  {
  	int ret_val;
  	struct netlbl_dom_map *entry;
  
  	rcu_read_lock();
  	if (domain)
  		entry = netlbl_domhsh_search(domain);
  	else
  		entry = netlbl_domhsh_search_def(domain);
  	ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
  	rcu_read_unlock();
d15c345fe   Paul Moore   [NetLabel]: core ...
575
576
577
578
579
  	return ret_val;
  }
  
  /**
   * netlbl_domhsh_remove_default - Removes the default entry from the table
95d4e6be2   Paul Moore   [NetLabel]: audit...
580
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
581
582
583
584
585
586
587
   *
   * Description:
   * Removes/resets the default entry for the domain hash table and handles any
   * updates to the lower level protocol handler (i.e. CIPSO).  Returns zero on
   * success, non-zero on failure.
   *
   */
95d4e6be2   Paul Moore   [NetLabel]: audit...
588
  int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
589
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
590
  	return netlbl_domhsh_remove(NULL, audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
591
592
593
594
595
596
597
598
  }
  
  /**
   * netlbl_domhsh_getentry - Get an entry from the domain hash table
   * @domain: the domain name to search for
   *
   * Description:
   * Look through the domain hash table searching for an entry to match @domain,
25985edce   Lucas De Marchi   Fix common misspe...
599
   * return a pointer to a copy of the entry or NULL.  The caller is responsible
d15c345fe   Paul Moore   [NetLabel]: core ...
600
601
602
603
604
   * for ensuring that rcu_read_[un]lock() is called.
   *
   */
  struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
  {
b64397e0b   Paul Moore   NetLabel: Cleanup...
605
  	return netlbl_domhsh_search_def(domain);
d15c345fe   Paul Moore   [NetLabel]: core ...
606
607
608
  }
  
  /**
63c416887   Paul Moore   netlabel: Add net...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
   * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
   * @domain: the domain name to search for
   * @addr: the IP address to search for
   *
   * Description:
   * Look through the domain hash table searching for an entry to match @domain
   * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
   * responsible for ensuring that rcu_read_[un]lock() is called.
   *
   */
  struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
  						       __be32 addr)
  {
  	struct netlbl_dom_map *dom_iter;
  	struct netlbl_af4list *addr_iter;
  
  	dom_iter = netlbl_domhsh_search_def(domain);
  	if (dom_iter == NULL)
  		return NULL;
  	if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
  		return NULL;
  
  	addr_iter = netlbl_af4list_search(addr,
  					  &dom_iter->type_def.addrsel->list4);
  	if (addr_iter == NULL)
  		return NULL;
  
  	return netlbl_domhsh_addr4_entry(addr_iter);
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
638
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  /**
   * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
   * @domain: the domain name to search for
   * @addr: the IP address to search for
   *
   * Description:
   * Look through the domain hash table searching for an entry to match @domain
   * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
   * responsible for ensuring that rcu_read_[un]lock() is called.
   *
   */
  struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
  						   const struct in6_addr *addr)
  {
  	struct netlbl_dom_map *dom_iter;
  	struct netlbl_af6list *addr_iter;
  
  	dom_iter = netlbl_domhsh_search_def(domain);
  	if (dom_iter == NULL)
  		return NULL;
  	if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
  		return NULL;
  
  	addr_iter = netlbl_af6list_search(addr,
  					  &dom_iter->type_def.addrsel->list6);
  	if (addr_iter == NULL)
  		return NULL;
  
  	return netlbl_domhsh_addr6_entry(addr_iter);
  }
  #endif /* IPv6 */
  
  /**
fcd482806   Paul Moore   [NetLabel]: rewor...
672
673
674
675
676
   * netlbl_domhsh_walk - Iterate through the domain mapping hash table
   * @skip_bkt: the number of buckets to skip at the start
   * @skip_chain: the number of entries to skip in the first iterated bucket
   * @callback: callback for each entry
   * @cb_arg: argument for the callback function
d15c345fe   Paul Moore   [NetLabel]: core ...
677
678
   *
   * Description:
fcd482806   Paul Moore   [NetLabel]: rewor...
679
680
681
682
   * Interate over the domain mapping hash table, skipping the first @skip_bkt
   * buckets and @skip_chain entries.  For each entry in the table call
   * @callback, if @callback returns a negative value stop 'walking' through the
   * table and return.  Updates the values in @skip_bkt and @skip_chain on
af901ca18   AndrĂ© Goddard Rosa   tree-wide: fix as...
683
   * return.  Returns zero on success, negative values on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
684
685
   *
   */
fcd482806   Paul Moore   [NetLabel]: rewor...
686
687
688
689
  int netlbl_domhsh_walk(u32 *skip_bkt,
  		     u32 *skip_chain,
  		     int (*callback) (struct netlbl_dom_map *entry, void *arg),
  		     void *cb_arg)
d15c345fe   Paul Moore   [NetLabel]: core ...
690
  {
fcd482806   Paul Moore   [NetLabel]: rewor...
691
692
  	int ret_val = -ENOENT;
  	u32 iter_bkt;
561967010   Paul Moore   netlabel: Fix som...
693
  	struct list_head *iter_list;
fcd482806   Paul Moore   [NetLabel]: rewor...
694
695
  	struct netlbl_dom_map *iter_entry;
  	u32 chain_cnt = 0;
d15c345fe   Paul Moore   [NetLabel]: core ...
696

d15c345fe   Paul Moore   [NetLabel]: core ...
697
  	rcu_read_lock();
fcd482806   Paul Moore   [NetLabel]: rewor...
698
699
700
  	for (iter_bkt = *skip_bkt;
  	     iter_bkt < rcu_dereference(netlbl_domhsh)->size;
  	     iter_bkt++, chain_cnt = 0) {
561967010   Paul Moore   netlabel: Fix som...
701
702
  		iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
  		list_for_each_entry_rcu(iter_entry, iter_list, list)
fcd482806   Paul Moore   [NetLabel]: rewor...
703
704
705
706
707
708
709
710
  			if (iter_entry->valid) {
  				if (chain_cnt++ < *skip_chain)
  					continue;
  				ret_val = callback(iter_entry, cb_arg);
  				if (ret_val < 0) {
  					chain_cnt--;
  					goto walk_return;
  				}
d15c345fe   Paul Moore   [NetLabel]: core ...
711
  			}
fcd482806   Paul Moore   [NetLabel]: rewor...
712
  	}
d15c345fe   Paul Moore   [NetLabel]: core ...
713

fcd482806   Paul Moore   [NetLabel]: rewor...
714
  walk_return:
d15c345fe   Paul Moore   [NetLabel]: core ...
715
  	rcu_read_unlock();
fcd482806   Paul Moore   [NetLabel]: rewor...
716
717
718
  	*skip_bkt = iter_bkt;
  	*skip_chain = chain_cnt;
  	return ret_val;
d15c345fe   Paul Moore   [NetLabel]: core ...
719
  }