xref: /OK3568_Linux_fs/kernel/security/selinux/ss/avtab.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Implementation of the access vector table type.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Author : Stephen Smalley, <sds@tycho.nsa.gov>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *	Added conditional policy language extensions
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Copyright (C) 2003 Tresys Technology, LLC
12*4882a593Smuzhiyun  *	This program is free software; you can redistribute it and/or modify
13*4882a593Smuzhiyun  *	it under the terms of the GNU General Public License as published by
14*4882a593Smuzhiyun  *	the Free Software Foundation, version 2.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
17*4882a593Smuzhiyun  *	Tuned number of hash slots for avtab to reduce memory usage
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/kernel.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/errno.h>
23*4882a593Smuzhiyun #include "avtab.h"
24*4882a593Smuzhiyun #include "policydb.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static struct kmem_cache *avtab_node_cachep;
27*4882a593Smuzhiyun static struct kmem_cache *avtab_xperms_cachep;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* Based on MurmurHash3, written by Austin Appleby and placed in the
30*4882a593Smuzhiyun  * public domain.
31*4882a593Smuzhiyun  */
avtab_hash(struct avtab_key * keyp,u32 mask)32*4882a593Smuzhiyun static inline int avtab_hash(struct avtab_key *keyp, u32 mask)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	static const u32 c1 = 0xcc9e2d51;
35*4882a593Smuzhiyun 	static const u32 c2 = 0x1b873593;
36*4882a593Smuzhiyun 	static const u32 r1 = 15;
37*4882a593Smuzhiyun 	static const u32 r2 = 13;
38*4882a593Smuzhiyun 	static const u32 m  = 5;
39*4882a593Smuzhiyun 	static const u32 n  = 0xe6546b64;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	u32 hash = 0;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define mix(input) { \
44*4882a593Smuzhiyun 	u32 v = input; \
45*4882a593Smuzhiyun 	v *= c1; \
46*4882a593Smuzhiyun 	v = (v << r1) | (v >> (32 - r1)); \
47*4882a593Smuzhiyun 	v *= c2; \
48*4882a593Smuzhiyun 	hash ^= v; \
49*4882a593Smuzhiyun 	hash = (hash << r2) | (hash >> (32 - r2)); \
50*4882a593Smuzhiyun 	hash = hash * m + n; \
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	mix(keyp->target_class);
54*4882a593Smuzhiyun 	mix(keyp->target_type);
55*4882a593Smuzhiyun 	mix(keyp->source_type);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #undef mix
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	hash ^= hash >> 16;
60*4882a593Smuzhiyun 	hash *= 0x85ebca6b;
61*4882a593Smuzhiyun 	hash ^= hash >> 13;
62*4882a593Smuzhiyun 	hash *= 0xc2b2ae35;
63*4882a593Smuzhiyun 	hash ^= hash >> 16;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return hash & mask;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun static struct avtab_node*
avtab_insert_node(struct avtab * h,int hvalue,struct avtab_node * prev,struct avtab_node * cur,struct avtab_key * key,struct avtab_datum * datum)69*4882a593Smuzhiyun avtab_insert_node(struct avtab *h, int hvalue,
70*4882a593Smuzhiyun 		  struct avtab_node *prev, struct avtab_node *cur,
71*4882a593Smuzhiyun 		  struct avtab_key *key, struct avtab_datum *datum)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct avtab_node *newnode;
74*4882a593Smuzhiyun 	struct avtab_extended_perms *xperms;
75*4882a593Smuzhiyun 	newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
76*4882a593Smuzhiyun 	if (newnode == NULL)
77*4882a593Smuzhiyun 		return NULL;
78*4882a593Smuzhiyun 	newnode->key = *key;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (key->specified & AVTAB_XPERMS) {
81*4882a593Smuzhiyun 		xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL);
82*4882a593Smuzhiyun 		if (xperms == NULL) {
83*4882a593Smuzhiyun 			kmem_cache_free(avtab_node_cachep, newnode);
84*4882a593Smuzhiyun 			return NULL;
85*4882a593Smuzhiyun 		}
86*4882a593Smuzhiyun 		*xperms = *(datum->u.xperms);
87*4882a593Smuzhiyun 		newnode->datum.u.xperms = xperms;
88*4882a593Smuzhiyun 	} else {
89*4882a593Smuzhiyun 		newnode->datum.u.data = datum->u.data;
90*4882a593Smuzhiyun 	}
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (prev) {
93*4882a593Smuzhiyun 		newnode->next = prev->next;
94*4882a593Smuzhiyun 		prev->next = newnode;
95*4882a593Smuzhiyun 	} else {
96*4882a593Smuzhiyun 		struct avtab_node **n = &h->htable[hvalue];
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		newnode->next = *n;
99*4882a593Smuzhiyun 		*n = newnode;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	h->nel++;
103*4882a593Smuzhiyun 	return newnode;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
avtab_insert(struct avtab * h,struct avtab_key * key,struct avtab_datum * datum)106*4882a593Smuzhiyun static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	int hvalue;
109*4882a593Smuzhiyun 	struct avtab_node *prev, *cur, *newnode;
110*4882a593Smuzhiyun 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	if (!h || !h->nslot)
113*4882a593Smuzhiyun 		return -EINVAL;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	hvalue = avtab_hash(key, h->mask);
116*4882a593Smuzhiyun 	for (prev = NULL, cur = h->htable[hvalue];
117*4882a593Smuzhiyun 	     cur;
118*4882a593Smuzhiyun 	     prev = cur, cur = cur->next) {
119*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
120*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
121*4882a593Smuzhiyun 		    key->target_class == cur->key.target_class &&
122*4882a593Smuzhiyun 		    (specified & cur->key.specified)) {
123*4882a593Smuzhiyun 			/* extended perms may not be unique */
124*4882a593Smuzhiyun 			if (specified & AVTAB_XPERMS)
125*4882a593Smuzhiyun 				break;
126*4882a593Smuzhiyun 			return -EEXIST;
127*4882a593Smuzhiyun 		}
128*4882a593Smuzhiyun 		if (key->source_type < cur->key.source_type)
129*4882a593Smuzhiyun 			break;
130*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
131*4882a593Smuzhiyun 		    key->target_type < cur->key.target_type)
132*4882a593Smuzhiyun 			break;
133*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
134*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
135*4882a593Smuzhiyun 		    key->target_class < cur->key.target_class)
136*4882a593Smuzhiyun 			break;
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
140*4882a593Smuzhiyun 	if (!newnode)
141*4882a593Smuzhiyun 		return -ENOMEM;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /* Unlike avtab_insert(), this function allow multiple insertions of the same
147*4882a593Smuzhiyun  * key/specified mask into the table, as needed by the conditional avtab.
148*4882a593Smuzhiyun  * It also returns a pointer to the node inserted.
149*4882a593Smuzhiyun  */
150*4882a593Smuzhiyun struct avtab_node *
avtab_insert_nonunique(struct avtab * h,struct avtab_key * key,struct avtab_datum * datum)151*4882a593Smuzhiyun avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	int hvalue;
154*4882a593Smuzhiyun 	struct avtab_node *prev, *cur;
155*4882a593Smuzhiyun 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (!h || !h->nslot)
158*4882a593Smuzhiyun 		return NULL;
159*4882a593Smuzhiyun 	hvalue = avtab_hash(key, h->mask);
160*4882a593Smuzhiyun 	for (prev = NULL, cur = h->htable[hvalue];
161*4882a593Smuzhiyun 	     cur;
162*4882a593Smuzhiyun 	     prev = cur, cur = cur->next) {
163*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
164*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
165*4882a593Smuzhiyun 		    key->target_class == cur->key.target_class &&
166*4882a593Smuzhiyun 		    (specified & cur->key.specified))
167*4882a593Smuzhiyun 			break;
168*4882a593Smuzhiyun 		if (key->source_type < cur->key.source_type)
169*4882a593Smuzhiyun 			break;
170*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
171*4882a593Smuzhiyun 		    key->target_type < cur->key.target_type)
172*4882a593Smuzhiyun 			break;
173*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
174*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
175*4882a593Smuzhiyun 		    key->target_class < cur->key.target_class)
176*4882a593Smuzhiyun 			break;
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 	return avtab_insert_node(h, hvalue, prev, cur, key, datum);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
avtab_search(struct avtab * h,struct avtab_key * key)181*4882a593Smuzhiyun struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	int hvalue;
184*4882a593Smuzhiyun 	struct avtab_node *cur;
185*4882a593Smuzhiyun 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (!h || !h->nslot)
188*4882a593Smuzhiyun 		return NULL;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	hvalue = avtab_hash(key, h->mask);
191*4882a593Smuzhiyun 	for (cur = h->htable[hvalue]; cur;
192*4882a593Smuzhiyun 	     cur = cur->next) {
193*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
194*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
195*4882a593Smuzhiyun 		    key->target_class == cur->key.target_class &&
196*4882a593Smuzhiyun 		    (specified & cur->key.specified))
197*4882a593Smuzhiyun 			return &cur->datum;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		if (key->source_type < cur->key.source_type)
200*4882a593Smuzhiyun 			break;
201*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
202*4882a593Smuzhiyun 		    key->target_type < cur->key.target_type)
203*4882a593Smuzhiyun 			break;
204*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
205*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
206*4882a593Smuzhiyun 		    key->target_class < cur->key.target_class)
207*4882a593Smuzhiyun 			break;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	return NULL;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /* This search function returns a node pointer, and can be used in
214*4882a593Smuzhiyun  * conjunction with avtab_search_next_node()
215*4882a593Smuzhiyun  */
216*4882a593Smuzhiyun struct avtab_node*
avtab_search_node(struct avtab * h,struct avtab_key * key)217*4882a593Smuzhiyun avtab_search_node(struct avtab *h, struct avtab_key *key)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int hvalue;
220*4882a593Smuzhiyun 	struct avtab_node *cur;
221*4882a593Smuzhiyun 	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (!h || !h->nslot)
224*4882a593Smuzhiyun 		return NULL;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	hvalue = avtab_hash(key, h->mask);
227*4882a593Smuzhiyun 	for (cur = h->htable[hvalue]; cur;
228*4882a593Smuzhiyun 	     cur = cur->next) {
229*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
230*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
231*4882a593Smuzhiyun 		    key->target_class == cur->key.target_class &&
232*4882a593Smuzhiyun 		    (specified & cur->key.specified))
233*4882a593Smuzhiyun 			return cur;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 		if (key->source_type < cur->key.source_type)
236*4882a593Smuzhiyun 			break;
237*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
238*4882a593Smuzhiyun 		    key->target_type < cur->key.target_type)
239*4882a593Smuzhiyun 			break;
240*4882a593Smuzhiyun 		if (key->source_type == cur->key.source_type &&
241*4882a593Smuzhiyun 		    key->target_type == cur->key.target_type &&
242*4882a593Smuzhiyun 		    key->target_class < cur->key.target_class)
243*4882a593Smuzhiyun 			break;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 	return NULL;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun struct avtab_node*
avtab_search_node_next(struct avtab_node * node,int specified)249*4882a593Smuzhiyun avtab_search_node_next(struct avtab_node *node, int specified)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct avtab_node *cur;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (!node)
254*4882a593Smuzhiyun 		return NULL;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
257*4882a593Smuzhiyun 	for (cur = node->next; cur; cur = cur->next) {
258*4882a593Smuzhiyun 		if (node->key.source_type == cur->key.source_type &&
259*4882a593Smuzhiyun 		    node->key.target_type == cur->key.target_type &&
260*4882a593Smuzhiyun 		    node->key.target_class == cur->key.target_class &&
261*4882a593Smuzhiyun 		    (specified & cur->key.specified))
262*4882a593Smuzhiyun 			return cur;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 		if (node->key.source_type < cur->key.source_type)
265*4882a593Smuzhiyun 			break;
266*4882a593Smuzhiyun 		if (node->key.source_type == cur->key.source_type &&
267*4882a593Smuzhiyun 		    node->key.target_type < cur->key.target_type)
268*4882a593Smuzhiyun 			break;
269*4882a593Smuzhiyun 		if (node->key.source_type == cur->key.source_type &&
270*4882a593Smuzhiyun 		    node->key.target_type == cur->key.target_type &&
271*4882a593Smuzhiyun 		    node->key.target_class < cur->key.target_class)
272*4882a593Smuzhiyun 			break;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 	return NULL;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
avtab_destroy(struct avtab * h)277*4882a593Smuzhiyun void avtab_destroy(struct avtab *h)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	int i;
280*4882a593Smuzhiyun 	struct avtab_node *cur, *temp;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if (!h)
283*4882a593Smuzhiyun 		return;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	for (i = 0; i < h->nslot; i++) {
286*4882a593Smuzhiyun 		cur = h->htable[i];
287*4882a593Smuzhiyun 		while (cur) {
288*4882a593Smuzhiyun 			temp = cur;
289*4882a593Smuzhiyun 			cur = cur->next;
290*4882a593Smuzhiyun 			if (temp->key.specified & AVTAB_XPERMS)
291*4882a593Smuzhiyun 				kmem_cache_free(avtab_xperms_cachep,
292*4882a593Smuzhiyun 						temp->datum.u.xperms);
293*4882a593Smuzhiyun 			kmem_cache_free(avtab_node_cachep, temp);
294*4882a593Smuzhiyun 		}
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun 	kvfree(h->htable);
297*4882a593Smuzhiyun 	h->htable = NULL;
298*4882a593Smuzhiyun 	h->nel = 0;
299*4882a593Smuzhiyun 	h->nslot = 0;
300*4882a593Smuzhiyun 	h->mask = 0;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
avtab_init(struct avtab * h)303*4882a593Smuzhiyun void avtab_init(struct avtab *h)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	h->htable = NULL;
306*4882a593Smuzhiyun 	h->nel = 0;
307*4882a593Smuzhiyun 	h->nslot = 0;
308*4882a593Smuzhiyun 	h->mask = 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
avtab_alloc_common(struct avtab * h,u32 nslot)311*4882a593Smuzhiyun static int avtab_alloc_common(struct avtab *h, u32 nslot)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	if (!nslot)
314*4882a593Smuzhiyun 		return 0;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL);
317*4882a593Smuzhiyun 	if (!h->htable)
318*4882a593Smuzhiyun 		return -ENOMEM;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	h->nslot = nslot;
321*4882a593Smuzhiyun 	h->mask = nslot - 1;
322*4882a593Smuzhiyun 	return 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
avtab_alloc(struct avtab * h,u32 nrules)325*4882a593Smuzhiyun int avtab_alloc(struct avtab *h, u32 nrules)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	int rc;
328*4882a593Smuzhiyun 	u32 nslot = 0;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (nrules != 0) {
331*4882a593Smuzhiyun 		u32 shift = 1;
332*4882a593Smuzhiyun 		u32 work = nrules >> 3;
333*4882a593Smuzhiyun 		while (work) {
334*4882a593Smuzhiyun 			work >>= 1;
335*4882a593Smuzhiyun 			shift++;
336*4882a593Smuzhiyun 		}
337*4882a593Smuzhiyun 		nslot = 1 << shift;
338*4882a593Smuzhiyun 		if (nslot > MAX_AVTAB_HASH_BUCKETS)
339*4882a593Smuzhiyun 			nslot = MAX_AVTAB_HASH_BUCKETS;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 		rc = avtab_alloc_common(h, nslot);
342*4882a593Smuzhiyun 		if (rc)
343*4882a593Smuzhiyun 			return rc;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	pr_debug("SELinux: %d avtab hash slots, %d rules.\n", nslot, nrules);
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
avtab_alloc_dup(struct avtab * new,const struct avtab * orig)350*4882a593Smuzhiyun int avtab_alloc_dup(struct avtab *new, const struct avtab *orig)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	return avtab_alloc_common(new, orig->nslot);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
avtab_hash_eval(struct avtab * h,char * tag)355*4882a593Smuzhiyun void avtab_hash_eval(struct avtab *h, char *tag)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	int i, chain_len, slots_used, max_chain_len;
358*4882a593Smuzhiyun 	unsigned long long chain2_len_sum;
359*4882a593Smuzhiyun 	struct avtab_node *cur;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	slots_used = 0;
362*4882a593Smuzhiyun 	max_chain_len = 0;
363*4882a593Smuzhiyun 	chain2_len_sum = 0;
364*4882a593Smuzhiyun 	for (i = 0; i < h->nslot; i++) {
365*4882a593Smuzhiyun 		cur = h->htable[i];
366*4882a593Smuzhiyun 		if (cur) {
367*4882a593Smuzhiyun 			slots_used++;
368*4882a593Smuzhiyun 			chain_len = 0;
369*4882a593Smuzhiyun 			while (cur) {
370*4882a593Smuzhiyun 				chain_len++;
371*4882a593Smuzhiyun 				cur = cur->next;
372*4882a593Smuzhiyun 			}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 			if (chain_len > max_chain_len)
375*4882a593Smuzhiyun 				max_chain_len = chain_len;
376*4882a593Smuzhiyun 			chain2_len_sum += chain_len * chain_len;
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	pr_debug("SELinux: %s:  %d entries and %d/%d buckets used, "
381*4882a593Smuzhiyun 	       "longest chain length %d sum of chain length^2 %llu\n",
382*4882a593Smuzhiyun 	       tag, h->nel, slots_used, h->nslot, max_chain_len,
383*4882a593Smuzhiyun 	       chain2_len_sum);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun static uint16_t spec_order[] = {
387*4882a593Smuzhiyun 	AVTAB_ALLOWED,
388*4882a593Smuzhiyun 	AVTAB_AUDITDENY,
389*4882a593Smuzhiyun 	AVTAB_AUDITALLOW,
390*4882a593Smuzhiyun 	AVTAB_TRANSITION,
391*4882a593Smuzhiyun 	AVTAB_CHANGE,
392*4882a593Smuzhiyun 	AVTAB_MEMBER,
393*4882a593Smuzhiyun 	AVTAB_XPERMS_ALLOWED,
394*4882a593Smuzhiyun 	AVTAB_XPERMS_AUDITALLOW,
395*4882a593Smuzhiyun 	AVTAB_XPERMS_DONTAUDIT
396*4882a593Smuzhiyun };
397*4882a593Smuzhiyun 
avtab_read_item(struct avtab * a,void * fp,struct policydb * pol,int (* insertf)(struct avtab * a,struct avtab_key * k,struct avtab_datum * d,void * p),void * p)398*4882a593Smuzhiyun int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
399*4882a593Smuzhiyun 		    int (*insertf)(struct avtab *a, struct avtab_key *k,
400*4882a593Smuzhiyun 				   struct avtab_datum *d, void *p),
401*4882a593Smuzhiyun 		    void *p)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	__le16 buf16[4];
404*4882a593Smuzhiyun 	u16 enabled;
405*4882a593Smuzhiyun 	u32 items, items2, val, vers = pol->policyvers;
406*4882a593Smuzhiyun 	struct avtab_key key;
407*4882a593Smuzhiyun 	struct avtab_datum datum;
408*4882a593Smuzhiyun 	struct avtab_extended_perms xperms;
409*4882a593Smuzhiyun 	__le32 buf32[ARRAY_SIZE(xperms.perms.p)];
410*4882a593Smuzhiyun 	int i, rc;
411*4882a593Smuzhiyun 	unsigned set;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	memset(&key, 0, sizeof(struct avtab_key));
414*4882a593Smuzhiyun 	memset(&datum, 0, sizeof(struct avtab_datum));
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	if (vers < POLICYDB_VERSION_AVTAB) {
417*4882a593Smuzhiyun 		rc = next_entry(buf32, fp, sizeof(u32));
418*4882a593Smuzhiyun 		if (rc) {
419*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
420*4882a593Smuzhiyun 			return rc;
421*4882a593Smuzhiyun 		}
422*4882a593Smuzhiyun 		items2 = le32_to_cpu(buf32[0]);
423*4882a593Smuzhiyun 		if (items2 > ARRAY_SIZE(buf32)) {
424*4882a593Smuzhiyun 			pr_err("SELinux: avtab: entry overflow\n");
425*4882a593Smuzhiyun 			return -EINVAL;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 		}
428*4882a593Smuzhiyun 		rc = next_entry(buf32, fp, sizeof(u32)*items2);
429*4882a593Smuzhiyun 		if (rc) {
430*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
431*4882a593Smuzhiyun 			return rc;
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 		items = 0;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 		val = le32_to_cpu(buf32[items++]);
436*4882a593Smuzhiyun 		key.source_type = (u16)val;
437*4882a593Smuzhiyun 		if (key.source_type != val) {
438*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated source type\n");
439*4882a593Smuzhiyun 			return -EINVAL;
440*4882a593Smuzhiyun 		}
441*4882a593Smuzhiyun 		val = le32_to_cpu(buf32[items++]);
442*4882a593Smuzhiyun 		key.target_type = (u16)val;
443*4882a593Smuzhiyun 		if (key.target_type != val) {
444*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated target type\n");
445*4882a593Smuzhiyun 			return -EINVAL;
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun 		val = le32_to_cpu(buf32[items++]);
448*4882a593Smuzhiyun 		key.target_class = (u16)val;
449*4882a593Smuzhiyun 		if (key.target_class != val) {
450*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated target class\n");
451*4882a593Smuzhiyun 			return -EINVAL;
452*4882a593Smuzhiyun 		}
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 		val = le32_to_cpu(buf32[items++]);
455*4882a593Smuzhiyun 		enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
458*4882a593Smuzhiyun 			pr_err("SELinux: avtab: null entry\n");
459*4882a593Smuzhiyun 			return -EINVAL;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 		if ((val & AVTAB_AV) &&
462*4882a593Smuzhiyun 		    (val & AVTAB_TYPE)) {
463*4882a593Smuzhiyun 			pr_err("SELinux: avtab: entry has both access vectors and types\n");
464*4882a593Smuzhiyun 			return -EINVAL;
465*4882a593Smuzhiyun 		}
466*4882a593Smuzhiyun 		if (val & AVTAB_XPERMS) {
467*4882a593Smuzhiyun 			pr_err("SELinux: avtab: entry has extended permissions\n");
468*4882a593Smuzhiyun 			return -EINVAL;
469*4882a593Smuzhiyun 		}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
472*4882a593Smuzhiyun 			if (val & spec_order[i]) {
473*4882a593Smuzhiyun 				key.specified = spec_order[i] | enabled;
474*4882a593Smuzhiyun 				datum.u.data = le32_to_cpu(buf32[items++]);
475*4882a593Smuzhiyun 				rc = insertf(a, &key, &datum, p);
476*4882a593Smuzhiyun 				if (rc)
477*4882a593Smuzhiyun 					return rc;
478*4882a593Smuzhiyun 			}
479*4882a593Smuzhiyun 		}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 		if (items != items2) {
482*4882a593Smuzhiyun 			pr_err("SELinux: avtab: entry only had %d items, expected %d\n",
483*4882a593Smuzhiyun 			       items2, items);
484*4882a593Smuzhiyun 			return -EINVAL;
485*4882a593Smuzhiyun 		}
486*4882a593Smuzhiyun 		return 0;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	rc = next_entry(buf16, fp, sizeof(u16)*4);
490*4882a593Smuzhiyun 	if (rc) {
491*4882a593Smuzhiyun 		pr_err("SELinux: avtab: truncated entry\n");
492*4882a593Smuzhiyun 		return rc;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	items = 0;
496*4882a593Smuzhiyun 	key.source_type = le16_to_cpu(buf16[items++]);
497*4882a593Smuzhiyun 	key.target_type = le16_to_cpu(buf16[items++]);
498*4882a593Smuzhiyun 	key.target_class = le16_to_cpu(buf16[items++]);
499*4882a593Smuzhiyun 	key.specified = le16_to_cpu(buf16[items++]);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	if (!policydb_type_isvalid(pol, key.source_type) ||
502*4882a593Smuzhiyun 	    !policydb_type_isvalid(pol, key.target_type) ||
503*4882a593Smuzhiyun 	    !policydb_class_isvalid(pol, key.target_class)) {
504*4882a593Smuzhiyun 		pr_err("SELinux: avtab: invalid type or class\n");
505*4882a593Smuzhiyun 		return -EINVAL;
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	set = 0;
509*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
510*4882a593Smuzhiyun 		if (key.specified & spec_order[i])
511*4882a593Smuzhiyun 			set++;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 	if (!set || set > 1) {
514*4882a593Smuzhiyun 		pr_err("SELinux:  avtab:  more than one specifier\n");
515*4882a593Smuzhiyun 		return -EINVAL;
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
519*4882a593Smuzhiyun 			(key.specified & AVTAB_XPERMS)) {
520*4882a593Smuzhiyun 		pr_err("SELinux:  avtab:  policy version %u does not "
521*4882a593Smuzhiyun 				"support extended permissions rules and one "
522*4882a593Smuzhiyun 				"was specified\n", vers);
523*4882a593Smuzhiyun 		return -EINVAL;
524*4882a593Smuzhiyun 	} else if (key.specified & AVTAB_XPERMS) {
525*4882a593Smuzhiyun 		memset(&xperms, 0, sizeof(struct avtab_extended_perms));
526*4882a593Smuzhiyun 		rc = next_entry(&xperms.specified, fp, sizeof(u8));
527*4882a593Smuzhiyun 		if (rc) {
528*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
529*4882a593Smuzhiyun 			return rc;
530*4882a593Smuzhiyun 		}
531*4882a593Smuzhiyun 		rc = next_entry(&xperms.driver, fp, sizeof(u8));
532*4882a593Smuzhiyun 		if (rc) {
533*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
534*4882a593Smuzhiyun 			return rc;
535*4882a593Smuzhiyun 		}
536*4882a593Smuzhiyun 		rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p));
537*4882a593Smuzhiyun 		if (rc) {
538*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
539*4882a593Smuzhiyun 			return rc;
540*4882a593Smuzhiyun 		}
541*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++)
542*4882a593Smuzhiyun 			xperms.perms.p[i] = le32_to_cpu(buf32[i]);
543*4882a593Smuzhiyun 		datum.u.xperms = &xperms;
544*4882a593Smuzhiyun 	} else {
545*4882a593Smuzhiyun 		rc = next_entry(buf32, fp, sizeof(u32));
546*4882a593Smuzhiyun 		if (rc) {
547*4882a593Smuzhiyun 			pr_err("SELinux: avtab: truncated entry\n");
548*4882a593Smuzhiyun 			return rc;
549*4882a593Smuzhiyun 		}
550*4882a593Smuzhiyun 		datum.u.data = le32_to_cpu(*buf32);
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 	if ((key.specified & AVTAB_TYPE) &&
553*4882a593Smuzhiyun 	    !policydb_type_isvalid(pol, datum.u.data)) {
554*4882a593Smuzhiyun 		pr_err("SELinux: avtab: invalid type\n");
555*4882a593Smuzhiyun 		return -EINVAL;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	return insertf(a, &key, &datum, p);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
avtab_insertf(struct avtab * a,struct avtab_key * k,struct avtab_datum * d,void * p)560*4882a593Smuzhiyun static int avtab_insertf(struct avtab *a, struct avtab_key *k,
561*4882a593Smuzhiyun 			 struct avtab_datum *d, void *p)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	return avtab_insert(a, k, d);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
avtab_read(struct avtab * a,void * fp,struct policydb * pol)566*4882a593Smuzhiyun int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	int rc;
569*4882a593Smuzhiyun 	__le32 buf[1];
570*4882a593Smuzhiyun 	u32 nel, i;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	rc = next_entry(buf, fp, sizeof(u32));
574*4882a593Smuzhiyun 	if (rc < 0) {
575*4882a593Smuzhiyun 		pr_err("SELinux: avtab: truncated table\n");
576*4882a593Smuzhiyun 		goto bad;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 	nel = le32_to_cpu(buf[0]);
579*4882a593Smuzhiyun 	if (!nel) {
580*4882a593Smuzhiyun 		pr_err("SELinux: avtab: table is empty\n");
581*4882a593Smuzhiyun 		rc = -EINVAL;
582*4882a593Smuzhiyun 		goto bad;
583*4882a593Smuzhiyun 	}
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	rc = avtab_alloc(a, nel);
586*4882a593Smuzhiyun 	if (rc)
587*4882a593Smuzhiyun 		goto bad;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	for (i = 0; i < nel; i++) {
590*4882a593Smuzhiyun 		rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
591*4882a593Smuzhiyun 		if (rc) {
592*4882a593Smuzhiyun 			if (rc == -ENOMEM)
593*4882a593Smuzhiyun 				pr_err("SELinux: avtab: out of memory\n");
594*4882a593Smuzhiyun 			else if (rc == -EEXIST)
595*4882a593Smuzhiyun 				pr_err("SELinux: avtab: duplicate entry\n");
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 			goto bad;
598*4882a593Smuzhiyun 		}
599*4882a593Smuzhiyun 	}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	rc = 0;
602*4882a593Smuzhiyun out:
603*4882a593Smuzhiyun 	return rc;
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun bad:
606*4882a593Smuzhiyun 	avtab_destroy(a);
607*4882a593Smuzhiyun 	goto out;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
avtab_write_item(struct policydb * p,struct avtab_node * cur,void * fp)610*4882a593Smuzhiyun int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	__le16 buf16[4];
613*4882a593Smuzhiyun 	__le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
614*4882a593Smuzhiyun 	int rc;
615*4882a593Smuzhiyun 	unsigned int i;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	buf16[0] = cpu_to_le16(cur->key.source_type);
618*4882a593Smuzhiyun 	buf16[1] = cpu_to_le16(cur->key.target_type);
619*4882a593Smuzhiyun 	buf16[2] = cpu_to_le16(cur->key.target_class);
620*4882a593Smuzhiyun 	buf16[3] = cpu_to_le16(cur->key.specified);
621*4882a593Smuzhiyun 	rc = put_entry(buf16, sizeof(u16), 4, fp);
622*4882a593Smuzhiyun 	if (rc)
623*4882a593Smuzhiyun 		return rc;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (cur->key.specified & AVTAB_XPERMS) {
626*4882a593Smuzhiyun 		rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp);
627*4882a593Smuzhiyun 		if (rc)
628*4882a593Smuzhiyun 			return rc;
629*4882a593Smuzhiyun 		rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp);
630*4882a593Smuzhiyun 		if (rc)
631*4882a593Smuzhiyun 			return rc;
632*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++)
633*4882a593Smuzhiyun 			buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]);
634*4882a593Smuzhiyun 		rc = put_entry(buf32, sizeof(u32),
635*4882a593Smuzhiyun 				ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
636*4882a593Smuzhiyun 	} else {
637*4882a593Smuzhiyun 		buf32[0] = cpu_to_le32(cur->datum.u.data);
638*4882a593Smuzhiyun 		rc = put_entry(buf32, sizeof(u32), 1, fp);
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun 	if (rc)
641*4882a593Smuzhiyun 		return rc;
642*4882a593Smuzhiyun 	return 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
avtab_write(struct policydb * p,struct avtab * a,void * fp)645*4882a593Smuzhiyun int avtab_write(struct policydb *p, struct avtab *a, void *fp)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	unsigned int i;
648*4882a593Smuzhiyun 	int rc = 0;
649*4882a593Smuzhiyun 	struct avtab_node *cur;
650*4882a593Smuzhiyun 	__le32 buf[1];
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	buf[0] = cpu_to_le32(a->nel);
653*4882a593Smuzhiyun 	rc = put_entry(buf, sizeof(u32), 1, fp);
654*4882a593Smuzhiyun 	if (rc)
655*4882a593Smuzhiyun 		return rc;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	for (i = 0; i < a->nslot; i++) {
658*4882a593Smuzhiyun 		for (cur = a->htable[i]; cur;
659*4882a593Smuzhiyun 		     cur = cur->next) {
660*4882a593Smuzhiyun 			rc = avtab_write_item(p, cur, fp);
661*4882a593Smuzhiyun 			if (rc)
662*4882a593Smuzhiyun 				return rc;
663*4882a593Smuzhiyun 		}
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return rc;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
avtab_cache_init(void)669*4882a593Smuzhiyun void __init avtab_cache_init(void)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun 	avtab_node_cachep = kmem_cache_create("avtab_node",
672*4882a593Smuzhiyun 					      sizeof(struct avtab_node),
673*4882a593Smuzhiyun 					      0, SLAB_PANIC, NULL);
674*4882a593Smuzhiyun 	avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms",
675*4882a593Smuzhiyun 						sizeof(struct avtab_extended_perms),
676*4882a593Smuzhiyun 						0, SLAB_PANIC, NULL);
677*4882a593Smuzhiyun }
678