Blame view

net/netlabel/netlabel_domainhash.c 22.1 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
   *
   * 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
d484ff154   Jeff Kirsher   netlabel: Fix FSF...
27
   * along with this program;  if not, see <http://www.gnu.org/licenses/>.
d15c345fe   Paul Moore   [NetLabel]: core ...
28
29
30
31
   *
   */
  
  #include <linux/types.h>
82524746c   Franck Bui-Huu   rcu: split list.h...
32
  #include <linux/rculist.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
33
34
35
  #include <linux/skbuff.h>
  #include <linux/spinlock.h>
  #include <linux/string.h>
32f50cdee   Paul Moore   [NetLabel]: add a...
36
  #include <linux/audit.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
37
  #include <linux/slab.h>
d15c345fe   Paul Moore   [NetLabel]: core ...
38
39
40
41
42
  #include <net/netlabel.h>
  #include <net/cipso_ipv4.h>
  #include <asm/bug.h>
  
  #include "netlabel_mgmt.h"
63c416887   Paul Moore   netlabel: Add net...
43
  #include "netlabel_addrlist.h"
d15c345fe   Paul Moore   [NetLabel]: core ...
44
  #include "netlabel_domainhash.h"
32f50cdee   Paul Moore   [NetLabel]: add a...
45
  #include "netlabel_user.h"
d15c345fe   Paul Moore   [NetLabel]: core ...
46
47
48
49
50
51
52
  
  struct netlbl_domhsh_tbl {
  	struct list_head *tbl;
  	u32 size;
  };
  
  /* Domain hash table */
b914f3a2a   Paul Moore   netlabel: Fix sev...
53
54
  /* updates should be so rare that having one spinlock for the entire hash table
   * should be okay */
8ce11e6a9   Adrian Bunk   [NET]: Make code ...
55
  static DEFINE_SPINLOCK(netlbl_domhsh_lock);
b914f3a2a   Paul Moore   netlabel: Fix sev...
56
  #define netlbl_domhsh_rcu_deref(p) \
d8bf4ca9c   Michal Hocko   rcu: treewide: Do...
57
  	rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
8303394d8   Wei Tang   netlabel: do not ...
58
59
  static struct netlbl_domhsh_tbl *netlbl_domhsh;
  static struct netlbl_dom_map *netlbl_domhsh_def;
d15c345fe   Paul Moore   [NetLabel]: core ...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  
  /*
   * 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...
78
79
  	struct netlbl_af4list *iter4;
  	struct netlbl_af4list *tmp4;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
80
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
81
82
83
  	struct netlbl_af6list *iter6;
  	struct netlbl_af6list *tmp6;
  #endif /* IPv6 */
d15c345fe   Paul Moore   [NetLabel]: core ...
84
85
  
  	ptr = container_of(entry, struct netlbl_dom_map, rcu);
6a8b7f0c8   Paul Moore   netlabel: use dom...
86
  	if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
63c416887   Paul Moore   netlabel: Add net...
87
  		netlbl_af4list_foreach_safe(iter4, tmp4,
6a8b7f0c8   Paul Moore   netlabel: use dom...
88
  					    &ptr->def.addrsel->list4) {
63c416887   Paul Moore   netlabel: Add net...
89
90
91
  			netlbl_af4list_remove_entry(iter4);
  			kfree(netlbl_domhsh_addr4_entry(iter4));
  		}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
92
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
93
  		netlbl_af6list_foreach_safe(iter6, tmp6,
6a8b7f0c8   Paul Moore   netlabel: use dom...
94
  					    &ptr->def.addrsel->list6) {
63c416887   Paul Moore   netlabel: Add net...
95
96
97
98
99
  			netlbl_af6list_remove_entry(iter6);
  			kfree(netlbl_domhsh_addr6_entry(iter6));
  		}
  #endif /* IPv6 */
  	}
d15c345fe   Paul Moore   [NetLabel]: core ...
100
101
102
103
104
105
106
107
108
109
  	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...
110
   * correct bucket number for the domain.  The caller is responsible for
b914f3a2a   Paul Moore   netlabel: Fix sev...
111
112
   * ensuring that the hash table is protected with either a RCU read lock or the
   * hash table lock.
d15c345fe   Paul Moore   [NetLabel]: core ...
113
114
115
116
117
118
119
120
121
122
123
124
125
   *
   */
  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...
126
  	return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
d15c345fe   Paul Moore   [NetLabel]: core ...
127
128
129
130
131
  }
  
  /**
   * netlbl_domhsh_search - Search for a domain entry
   * @domain: the domain
d15c345fe   Paul Moore   [NetLabel]: core ...
132
133
134
   *
   * Description:
   * Searches the domain hash table and returns a pointer to the hash table
25985edce   Lucas De Marchi   Fix common misspe...
135
   * entry if found, otherwise NULL is returned.  The caller is responsible for
b914f3a2a   Paul Moore   netlabel: Fix sev...
136
137
   * ensuring that the hash table is protected with either a RCU read lock or the
   * hash table lock.
d15c345fe   Paul Moore   [NetLabel]: core ...
138
139
   *
   */
b64397e0b   Paul Moore   NetLabel: Cleanup...
140
  static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
d15c345fe   Paul Moore   [NetLabel]: core ...
141
142
  {
  	u32 bkt;
561967010   Paul Moore   netlabel: Fix som...
143
  	struct list_head *bkt_list;
d15c345fe   Paul Moore   [NetLabel]: core ...
144
145
146
147
  	struct netlbl_dom_map *iter;
  
  	if (domain != NULL) {
  		bkt = netlbl_domhsh_hash(domain);
b914f3a2a   Paul Moore   netlabel: Fix sev...
148
  		bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
561967010   Paul Moore   netlabel: Fix som...
149
  		list_for_each_entry_rcu(iter, bkt_list, list)
d15c345fe   Paul Moore   [NetLabel]: core ...
150
151
152
  			if (iter->valid && strcmp(iter->domain, domain) == 0)
  				return iter;
  	}
b64397e0b   Paul Moore   NetLabel: Cleanup...
153
154
155
156
157
158
159
160
161
162
163
164
  	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...
165
   * returned.  The caller is responsible ensuring that the hash table is
b914f3a2a   Paul Moore   netlabel: Fix sev...
166
   * protected with either a RCU read lock or the hash table lock.
b64397e0b   Paul Moore   NetLabel: Cleanup...
167
168
169
170
171
172
173
174
   *
   */
  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...
175
  		entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
4c3a0a254   Pavel Emelyanov   [NETLABEL]: Fix l...
176
177
  		if (entry != NULL && !entry->valid)
  			entry = NULL;
d15c345fe   Paul Moore   [NetLabel]: core ...
178
  	}
4c3a0a254   Pavel Emelyanov   [NETLABEL]: Fix l...
179
  	return entry;
d15c345fe   Paul Moore   [NetLabel]: core ...
180
  }
63c416887   Paul Moore   netlabel: Add net...
181
182
183
184
185
186
187
188
189
190
  /**
   * 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...
191
   * the given information.  Caller is responsible for holding the necessary
63c416887   Paul Moore   netlabel: Add net...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
   * 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);
6a8b7f0c8   Paul Moore   netlabel: use dom...
212
213
  			type = map4->def.type;
  			cipsov4 = map4->def.cipso;
63c416887   Paul Moore   netlabel: Add net...
214
215
  			netlbl_af4list_audit_addr(audit_buf, 0, NULL,
  						  addr4->addr, addr4->mask);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
216
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
217
218
219
  		} else if (addr6 != NULL) {
  			struct netlbl_domaddr6_map *map6;
  			map6 = netlbl_domhsh_addr6_entry(addr6);
6a8b7f0c8   Paul Moore   netlabel: use dom...
220
  			type = map6->def.type;
63c416887   Paul Moore   netlabel: Add net...
221
222
223
224
  			netlbl_af6list_audit_addr(audit_buf, 0, NULL,
  						  &addr6->addr, &addr6->mask);
  #endif /* IPv6 */
  		} else {
6a8b7f0c8   Paul Moore   netlabel: use dom...
225
226
  			type = entry->def.type;
  			cipsov4 = entry->def.cipso;
63c416887   Paul Moore   netlabel: Add net...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  		}
  		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);
  	}
  }
6b21e1b77   Paul Moore   netlabel: improve...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  /**
   * netlbl_domhsh_validate - Validate a new domain mapping entry
   * @entry: the entry to validate
   *
   * This function validates the new domain mapping entry to ensure that it is
   * a valid entry.  Returns zero on success, negative values on failure.
   *
   */
  static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
  {
  	struct netlbl_af4list *iter4;
  	struct netlbl_domaddr4_map *map4;
  #if IS_ENABLED(CONFIG_IPV6)
  	struct netlbl_af6list *iter6;
  	struct netlbl_domaddr6_map *map6;
  #endif /* IPv6 */
  
  	if (entry == NULL)
  		return -EINVAL;
6a8b7f0c8   Paul Moore   netlabel: use dom...
262
  	switch (entry->def.type) {
6b21e1b77   Paul Moore   netlabel: improve...
263
  	case NETLBL_NLTYPE_UNLABELED:
6a8b7f0c8   Paul Moore   netlabel: use dom...
264
  		if (entry->def.cipso != NULL || entry->def.addrsel != NULL)
6b21e1b77   Paul Moore   netlabel: improve...
265
266
267
  			return -EINVAL;
  		break;
  	case NETLBL_NLTYPE_CIPSOV4:
6a8b7f0c8   Paul Moore   netlabel: use dom...
268
  		if (entry->def.cipso == NULL)
6b21e1b77   Paul Moore   netlabel: improve...
269
270
271
  			return -EINVAL;
  		break;
  	case NETLBL_NLTYPE_ADDRSELECT:
6a8b7f0c8   Paul Moore   netlabel: use dom...
272
  		netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
6b21e1b77   Paul Moore   netlabel: improve...
273
  			map4 = netlbl_domhsh_addr4_entry(iter4);
6a8b7f0c8   Paul Moore   netlabel: use dom...
274
  			switch (map4->def.type) {
6b21e1b77   Paul Moore   netlabel: improve...
275
  			case NETLBL_NLTYPE_UNLABELED:
6a8b7f0c8   Paul Moore   netlabel: use dom...
276
  				if (map4->def.cipso != NULL)
6b21e1b77   Paul Moore   netlabel: improve...
277
278
279
  					return -EINVAL;
  				break;
  			case NETLBL_NLTYPE_CIPSOV4:
6a8b7f0c8   Paul Moore   netlabel: use dom...
280
  				if (map4->def.cipso == NULL)
6b21e1b77   Paul Moore   netlabel: improve...
281
282
283
284
285
286
287
  					return -EINVAL;
  				break;
  			default:
  				return -EINVAL;
  			}
  		}
  #if IS_ENABLED(CONFIG_IPV6)
6a8b7f0c8   Paul Moore   netlabel: use dom...
288
  		netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
6b21e1b77   Paul Moore   netlabel: improve...
289
  			map6 = netlbl_domhsh_addr6_entry(iter6);
6a8b7f0c8   Paul Moore   netlabel: use dom...
290
  			switch (map6->def.type) {
6b21e1b77   Paul Moore   netlabel: improve...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  			case NETLBL_NLTYPE_UNLABELED:
  				break;
  			default:
  				return -EINVAL;
  			}
  		}
  #endif /* IPv6 */
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
d15c345fe   Paul Moore   [NetLabel]: core ...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  /*
   * 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 ...
319
  int __init netlbl_domhsh_init(u32 size)
d15c345fe   Paul Moore   [NetLabel]: core ...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  {
  	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 ...
340
  	spin_lock(&netlbl_domhsh_lock);
cf778b00e   Eric Dumazet   net: reintroduce ...
341
  	rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
d15c345fe   Paul Moore   [NetLabel]: core ...
342
  	spin_unlock(&netlbl_domhsh_lock);
d15c345fe   Paul Moore   [NetLabel]: core ...
343
344
345
346
347
348
349
  
  	return 0;
  }
  
  /**
   * netlbl_domhsh_add - Adds a entry to the domain hash table
   * @entry: the entry to add
95d4e6be2   Paul Moore   [NetLabel]: audit...
350
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
351
352
353
354
355
356
357
   *
   * 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...
358
359
  int netlbl_domhsh_add(struct netlbl_dom_map *entry,
  		      struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
360
  {
63c416887   Paul Moore   netlabel: Add net...
361
362
363
364
  	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...
365
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
366
367
368
  	struct netlbl_af6list *iter6;
  	struct netlbl_af6list *tmp6;
  #endif /* IPv6 */
d15c345fe   Paul Moore   [NetLabel]: core ...
369

6b21e1b77   Paul Moore   netlabel: improve...
370
371
372
  	ret_val = netlbl_domhsh_validate(entry);
  	if (ret_val != 0)
  		return ret_val;
b914f3a2a   Paul Moore   netlabel: Fix sev...
373
374
375
376
  	/* 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 ...
377
  	rcu_read_lock();
1c3fad936   Paul Moore   NetLabel: Consoli...
378
  	spin_lock(&netlbl_domhsh_lock);
63c416887   Paul Moore   netlabel: Add net...
379
380
381
382
383
384
  	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...
385
386
387
  
  		if (entry->domain != NULL) {
  			u32 bkt = netlbl_domhsh_hash(entry->domain);
d15c345fe   Paul Moore   [NetLabel]: core ...
388
  			list_add_tail_rcu(&entry->list,
3482fd909   Paul Moore   [NetLabel]: add m...
389
  				    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
63c416887   Paul Moore   netlabel: Add net...
390
391
  		} else {
  			INIT_LIST_HEAD(&entry->list);
cf778b00e   Eric Dumazet   net: reintroduce ...
392
  			rcu_assign_pointer(netlbl_domhsh_def, entry);
de64688ff   Paul Moore   NetLabel: honor t...
393
  		}
d15c345fe   Paul Moore   [NetLabel]: core ...
394

6a8b7f0c8   Paul Moore   netlabel: use dom...
395
  		if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
63c416887   Paul Moore   netlabel: Add net...
396
  			netlbl_af4list_foreach_rcu(iter4,
6a8b7f0c8   Paul Moore   netlabel: use dom...
397
  						   &entry->def.addrsel->list4)
63c416887   Paul Moore   netlabel: Add net...
398
399
  				netlbl_domhsh_audit_add(entry, iter4, NULL,
  							ret_val, audit_info);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
400
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
401
  			netlbl_af6list_foreach_rcu(iter6,
6a8b7f0c8   Paul Moore   netlabel: use dom...
402
  						   &entry->def.addrsel->list6)
63c416887   Paul Moore   netlabel: Add net...
403
404
405
406
407
408
  				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);
6a8b7f0c8   Paul Moore   netlabel: use dom...
409
410
  	} else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
  		   entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
63c416887   Paul Moore   netlabel: Add net...
411
412
  		struct list_head *old_list4;
  		struct list_head *old_list6;
6a8b7f0c8   Paul Moore   netlabel: use dom...
413
414
  		old_list4 = &entry_old->def.addrsel->list4;
  		old_list6 = &entry_old->def.addrsel->list6;
63c416887   Paul Moore   netlabel: Add net...
415
416
417
  
  		/* we only allow the addition of address selectors if all of
  		 * the selectors do not exist in the existing domain map */
6a8b7f0c8   Paul Moore   netlabel: use dom...
418
  		netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
63c416887   Paul Moore   netlabel: Add net...
419
420
421
422
423
424
  			if (netlbl_af4list_search_exact(iter4->addr,
  							iter4->mask,
  							old_list4)) {
  				ret_val = -EEXIST;
  				goto add_return;
  			}
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
425
  #if IS_ENABLED(CONFIG_IPV6)
6a8b7f0c8   Paul Moore   netlabel: use dom...
426
  		netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
63c416887   Paul Moore   netlabel: Add net...
427
428
429
430
431
432
433
434
435
  			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,
6a8b7f0c8   Paul Moore   netlabel: use dom...
436
  					    &entry->def.addrsel->list4) {
63c416887   Paul Moore   netlabel: Add net...
437
438
439
440
441
442
443
444
  			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...
445
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
446
  		netlbl_af6list_foreach_safe(iter6, tmp6,
6a8b7f0c8   Paul Moore   netlabel: use dom...
447
  					    &entry->def.addrsel->list6) {
63c416887   Paul Moore   netlabel: Add net...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  			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 ...
463
464
465
466
467
468
  	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...
469
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
470
471
472
473
474
475
476
   *
   * 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...
477
478
  int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
  			      struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
479
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
480
  	return netlbl_domhsh_add(entry, audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
481
482
483
  }
  
  /**
b1edeb102   Paul Moore   netlabel: Replace...
484
485
   * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
   * @entry: the entry to remove
95d4e6be2   Paul Moore   [NetLabel]: audit...
486
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
487
488
489
   *
   * Description:
   * Removes an entry from the domain hash table and handles any updates to the
b1edeb102   Paul Moore   netlabel: Replace...
490
491
492
   * 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 ...
493
494
   *
   */
b1edeb102   Paul Moore   netlabel: Replace...
495
496
  int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
  			       struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
497
  {
b1edeb102   Paul Moore   netlabel: Replace...
498
  	int ret_val = 0;
32f50cdee   Paul Moore   [NetLabel]: add a...
499
  	struct audit_buffer *audit_buf;
d15c345fe   Paul Moore   [NetLabel]: core ...
500

d15c345fe   Paul Moore   [NetLabel]: core ...
501
  	if (entry == NULL)
b1edeb102   Paul Moore   netlabel: Replace...
502
  		return -ENOENT;
1c3fad936   Paul Moore   NetLabel: Consoli...
503
504
505
506
  	spin_lock(&netlbl_domhsh_lock);
  	if (entry->valid) {
  		entry->valid = 0;
  		if (entry != rcu_dereference(netlbl_domhsh_def))
d15c345fe   Paul Moore   [NetLabel]: core ...
507
  			list_del_rcu(&entry->list);
1c3fad936   Paul Moore   NetLabel: Consoli...
508
  		else
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
509
  			RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
b1edeb102   Paul Moore   netlabel: Replace...
510
511
  	} else
  		ret_val = -ENOENT;
1c3fad936   Paul Moore   NetLabel: Consoli...
512
  	spin_unlock(&netlbl_domhsh_lock);
32f50cdee   Paul Moore   [NetLabel]: add a...
513

95d4e6be2   Paul Moore   [NetLabel]: audit...
514
  	audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
de64688ff   Paul Moore   NetLabel: honor t...
515
516
517
518
519
520
521
  	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...
522

b1edeb102   Paul Moore   netlabel: Replace...
523
  	if (ret_val == 0) {
63c416887   Paul Moore   netlabel: Add net...
524
525
  		struct netlbl_af4list *iter4;
  		struct netlbl_domaddr4_map *map4;
6a8b7f0c8   Paul Moore   netlabel: use dom...
526
  		switch (entry->def.type) {
63c416887   Paul Moore   netlabel: Add net...
527
528
  		case NETLBL_NLTYPE_ADDRSELECT:
  			netlbl_af4list_foreach_rcu(iter4,
6a8b7f0c8   Paul Moore   netlabel: use dom...
529
  					     &entry->def.addrsel->list4) {
63c416887   Paul Moore   netlabel: Add net...
530
  				map4 = netlbl_domhsh_addr4_entry(iter4);
6a8b7f0c8   Paul Moore   netlabel: use dom...
531
  				cipso_v4_doi_putdef(map4->def.cipso);
63c416887   Paul Moore   netlabel: Add net...
532
533
534
535
  			}
  			/* no need to check the IPv6 list since we currently
  			 * support only unlabeled protocols for IPv6 */
  			break;
b1edeb102   Paul Moore   netlabel: Replace...
536
  		case NETLBL_NLTYPE_CIPSOV4:
6a8b7f0c8   Paul Moore   netlabel: use dom...
537
  			cipso_v4_doi_putdef(entry->def.cipso);
b1edeb102   Paul Moore   netlabel: Replace...
538
539
  			break;
  		}
4be2700fb   Paul Moore   [NetLabel]: corre...
540
  		call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
b1edeb102   Paul Moore   netlabel: Replace...
541
542
543
544
545
546
  	}
  
  	return ret_val;
  }
  
  /**
6c2e8ac09   Paul Moore   netlabel: Update ...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
   * 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...
567
  #if IS_ENABLED(CONFIG_IPV6)
6c2e8ac09   Paul Moore   netlabel: Update ...
568
569
570
571
572
573
574
575
576
577
  	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);
6a8b7f0c8   Paul Moore   netlabel: use dom...
578
579
  	if (entry_map == NULL ||
  	    entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
6c2e8ac09   Paul Moore   netlabel: Update ...
580
581
582
583
  		goto remove_af4_failure;
  
  	spin_lock(&netlbl_domhsh_lock);
  	entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
6a8b7f0c8   Paul Moore   netlabel: use dom...
584
  					   &entry_map->def.addrsel->list4);
6c2e8ac09   Paul Moore   netlabel: Update ...
585
586
587
588
  	spin_unlock(&netlbl_domhsh_lock);
  
  	if (entry_addr == NULL)
  		goto remove_af4_failure;
6a8b7f0c8   Paul Moore   netlabel: use dom...
589
  	netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
6c2e8ac09   Paul Moore   netlabel: Update ...
590
  		goto remove_af4_single_addr;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
591
  #if IS_ENABLED(CONFIG_IPV6)
6a8b7f0c8   Paul Moore   netlabel: use dom...
592
  	netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
6c2e8ac09   Paul Moore   netlabel: Update ...
593
594
595
596
597
598
599
600
601
602
603
604
  		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);
6a8b7f0c8   Paul Moore   netlabel: use dom...
605
  	cipso_v4_doi_putdef(entry->def.cipso);
6c2e8ac09   Paul Moore   netlabel: Update ...
606
607
608
609
610
611
612
613
614
  	kfree(entry);
  	return 0;
  
  remove_af4_failure:
  	rcu_read_unlock();
  	return -ENOENT;
  }
  
  /**
b1edeb102   Paul Moore   netlabel: Replace...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
   * 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 ...
637
638
639
640
641
  	return ret_val;
  }
  
  /**
   * netlbl_domhsh_remove_default - Removes the default entry from the table
95d4e6be2   Paul Moore   [NetLabel]: audit...
642
   * @audit_info: NetLabel audit information
d15c345fe   Paul Moore   [NetLabel]: core ...
643
644
645
646
647
648
649
   *
   * 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...
650
  int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
d15c345fe   Paul Moore   [NetLabel]: core ...
651
  {
95d4e6be2   Paul Moore   [NetLabel]: audit...
652
  	return netlbl_domhsh_remove(NULL, audit_info);
d15c345fe   Paul Moore   [NetLabel]: core ...
653
654
655
656
657
658
659
660
  }
  
  /**
   * 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...
661
   * return a pointer to a copy of the entry or NULL.  The caller is responsible
d15c345fe   Paul Moore   [NetLabel]: core ...
662
663
664
665
666
   * for ensuring that rcu_read_[un]lock() is called.
   *
   */
  struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
  {
b64397e0b   Paul Moore   NetLabel: Cleanup...
667
  	return netlbl_domhsh_search_def(domain);
d15c345fe   Paul Moore   [NetLabel]: core ...
668
669
670
  }
  
  /**
63c416887   Paul Moore   netlabel: Add net...
671
672
673
674
675
676
677
678
679
680
   * 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.
   *
   */
6a8b7f0c8   Paul Moore   netlabel: use dom...
681
682
  struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
  						     __be32 addr)
63c416887   Paul Moore   netlabel: Add net...
683
684
685
686
687
688
689
  {
  	struct netlbl_dom_map *dom_iter;
  	struct netlbl_af4list *addr_iter;
  
  	dom_iter = netlbl_domhsh_search_def(domain);
  	if (dom_iter == NULL)
  		return NULL;
63c416887   Paul Moore   netlabel: Add net...
690

6a8b7f0c8   Paul Moore   netlabel: use dom...
691
692
693
  	if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
  		return &dom_iter->def;
  	addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
63c416887   Paul Moore   netlabel: Add net...
694
695
  	if (addr_iter == NULL)
  		return NULL;
6a8b7f0c8   Paul Moore   netlabel: use dom...
696
  	return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
63c416887   Paul Moore   netlabel: Add net...
697
  }
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
698
  #if IS_ENABLED(CONFIG_IPV6)
63c416887   Paul Moore   netlabel: Add net...
699
700
701
702
703
704
705
706
707
708
709
  /**
   * 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.
   *
   */
6a8b7f0c8   Paul Moore   netlabel: use dom...
710
  struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
63c416887   Paul Moore   netlabel: Add net...
711
712
713
714
715
716
717
718
  						   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;
63c416887   Paul Moore   netlabel: Add net...
719

6a8b7f0c8   Paul Moore   netlabel: use dom...
720
721
722
  	if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
  		return &dom_iter->def;
  	addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
63c416887   Paul Moore   netlabel: Add net...
723
724
  	if (addr_iter == NULL)
  		return NULL;
6a8b7f0c8   Paul Moore   netlabel: use dom...
725
  	return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
63c416887   Paul Moore   netlabel: Add net...
726
727
728
729
  }
  #endif /* IPv6 */
  
  /**
fcd482806   Paul Moore   [NetLabel]: rewor...
730
731
732
733
734
   * 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 ...
735
736
   *
   * Description:
fcd482806   Paul Moore   [NetLabel]: rewor...
737
738
739
740
   * 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...
741
   * return.  Returns zero on success, negative values on failure.
d15c345fe   Paul Moore   [NetLabel]: core ...
742
743
   *
   */
fcd482806   Paul Moore   [NetLabel]: rewor...
744
745
746
747
  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 ...
748
  {
fcd482806   Paul Moore   [NetLabel]: rewor...
749
750
  	int ret_val = -ENOENT;
  	u32 iter_bkt;
561967010   Paul Moore   netlabel: Fix som...
751
  	struct list_head *iter_list;
fcd482806   Paul Moore   [NetLabel]: rewor...
752
753
  	struct netlbl_dom_map *iter_entry;
  	u32 chain_cnt = 0;
d15c345fe   Paul Moore   [NetLabel]: core ...
754

d15c345fe   Paul Moore   [NetLabel]: core ...
755
  	rcu_read_lock();
fcd482806   Paul Moore   [NetLabel]: rewor...
756
757
758
  	for (iter_bkt = *skip_bkt;
  	     iter_bkt < rcu_dereference(netlbl_domhsh)->size;
  	     iter_bkt++, chain_cnt = 0) {
561967010   Paul Moore   netlabel: Fix som...
759
760
  		iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
  		list_for_each_entry_rcu(iter_entry, iter_list, list)
fcd482806   Paul Moore   [NetLabel]: rewor...
761
762
763
764
765
766
767
768
  			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 ...
769
  			}
fcd482806   Paul Moore   [NetLabel]: rewor...
770
  	}
d15c345fe   Paul Moore   [NetLabel]: core ...
771

fcd482806   Paul Moore   [NetLabel]: rewor...
772
  walk_return:
d15c345fe   Paul Moore   [NetLabel]: core ...
773
  	rcu_read_unlock();
fcd482806   Paul Moore   [NetLabel]: rewor...
774
775
776
  	*skip_bkt = iter_bkt;
  	*skip_chain = chain_cnt;
  	return ret_val;
d15c345fe   Paul Moore   [NetLabel]: core ...
777
  }