xref: /minix/minix/lib/libsys/safecopies.c (revision 0a6a1f1d)
1 
2 /* Library functions to maintain internal data copying tables.
3  *
4  * April 21 2006: Initial version (Ben Gras)
5  *
6  */
7 
8 #include <lib.h>
9 #include <errno.h>
10 #include <minix/sysutil.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <minix/syslib.h>
14 #include <minix/safecopies.h>
15 #include <minix/com.h>
16 #include <string.h>
17 
18 #define ACCESS_CHECK(a) { 			\
19 	if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) {	\
20 		errno = EINVAL;			\
21 		return -1;			\
22 	}					\
23    }
24 
25 #define GID_CHECK(gid) {					\
26 	if(!GRANT_VALID(gid) || (gid) < 0 || (gid) >= ngrants) {\
27 		errno = EINVAL;					\
28 		return -1;					\
29 	}							\
30    }
31 
32 #define GID_CHECK_USED(gid) {					\
33 	GID_CHECK(gid);						\
34 	if(!(grants[gid].cp_flags & CPF_USED)) {		\
35 		errno = EINVAL;					\
36 		return -1;					\
37 	}							\
38    }
39 
40 #define CLICK_ALIGNMENT_CHECK(addr, bytes) {				      \
41 	if(((vir_bytes)(addr) % CLICK_SIZE != 0)			      \
42 		|| ((vir_bytes)(bytes) % CLICK_SIZE != 0)) {		      \
43 		return EINVAL;						      \
44 	}								      \
45    }
46 
47 #define NR_STATIC_GRANTS 3
48 static cp_grant_t static_grants[NR_STATIC_GRANTS];
49 static cp_grant_t *grants = NULL;
50 static int ngrants = 0;
51 
52 static void
53 cpf_grow(void)
54 {
55 /* Grow the grants table if possible. */
56 	cp_grant_t *new_grants;
57 	cp_grant_id_t g;
58 	int new_size;
59 
60 	if(!ngrants) {
61 		/* Use statically allocated grants the first time. */
62 		new_size = NR_STATIC_GRANTS;
63 		new_grants = static_grants;
64 	}
65 	else {
66 		new_size = (1+ngrants)*2;
67 		assert(new_size > ngrants);
68 
69 		/* Allocate a block of new size. */
70 		if(!(new_grants=malloc(new_size * sizeof(grants[0])))) {
71 			return;
72 		}
73 	}
74 
75 	/* Copy old block to new block. */
76 	if(grants && ngrants > 0)
77 		memcpy(new_grants, grants, ngrants * sizeof(grants[0]));
78 
79 	/* Make sure new slots are marked unused (CPF_USED is clear). */
80 	for(g = ngrants; g < new_size; g++)
81 		new_grants[g].cp_flags = 0;
82 
83 	/* Inform kernel about new size (and possibly new location). */
84 	if((sys_setgrant(new_grants, new_size))) {
85                 if(new_grants != static_grants) free(new_grants);
86 		return;	/* Failed - don't grow then. */
87 	}
88 
89 	/* Update internal data. */
90 	if(grants && ngrants > 0 && grants != static_grants) free(grants);
91 	grants = new_grants;
92 	ngrants = new_size;
93 }
94 
95 static cp_grant_id_t
96 cpf_new_grantslot(void)
97 {
98 /* Find a new, free grant slot in the grant table, grow it if
99  * necessary. If no free slot is found and the grow failed,
100  * return -1. Otherwise, return grant slot number.
101  */
102 	cp_grant_id_t g;
103 
104 	/* Find free slot. */
105 	for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++)
106 		;
107 
108 	assert(g <= ngrants);
109 
110 	/* No free slot found? */
111 	if(g == ngrants) {
112 		cpf_grow();
113 		assert(g <= ngrants); /* ngrants can't shrink. */
114 		if(g == ngrants) {
115 			/* ngrants hasn't increased. */
116 			errno = ENOSPC;
117 			return -1;
118 		}
119 	}
120 
121 	/* Basic sanity checks - if we get this far, g must be a valid,
122 	 * free slot.
123 	 */
124 	assert(GRANT_VALID(g));
125 	assert(g >= 0);
126 	assert(g < ngrants);
127 	assert(!(grants[g].cp_flags & CPF_USED));
128 
129 	return g;
130 }
131 
132 cp_grant_id_t
133 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access)
134 {
135 	cp_grant_id_t g;
136 	int r;
137 
138 	/* Get new slot to put new grant in. */
139 	if((g = cpf_new_grantslot()) < 0)
140 		return(GRANT_INVALID);
141 
142 	assert(GRANT_VALID(g));
143 	assert(g >= 0);
144 	assert(g < ngrants);
145 	assert(!(grants[g].cp_flags & CPF_USED));
146 
147 	if((r=cpf_setgrant_direct(g, who_to, addr, bytes, access)) < 0) {
148 		cpf_revoke(g);
149 		return(GRANT_INVALID);
150 	}
151 
152 	return g;
153 }
154 
155 cp_grant_id_t
156 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr)
157 {
158 /* Grant process A access into process B. B has granted us access as grant
159  * id 'gr'.
160  */
161 	cp_grant_id_t g;
162 	int r;
163 
164 	/* Obtain new slot. */
165 	if((g = cpf_new_grantslot()) < 0)
166 		return -1;
167 
168 	/* Basic sanity checks. */
169 	assert(GRANT_VALID(g));
170 	assert(g >= 0);
171 	assert(g < ngrants);
172 	assert(!(grants[g].cp_flags & CPF_USED));
173 
174 	/* Fill in new slot data. */
175 	if((r=cpf_setgrant_indirect(g, who_to, who_from, gr)) < 0) {
176 		cpf_revoke(g);
177 		return GRANT_INVALID;
178 	}
179 
180 	return g;
181 }
182 
183 cp_grant_id_t
184 cpf_grant_magic(endpoint_t who_to, endpoint_t who_from,
185 	vir_bytes addr, size_t bytes, int access)
186 {
187 /* Grant process A access into process B. Not everyone can do this. */
188 	cp_grant_id_t g;
189 	int r;
190 
191 	ACCESS_CHECK(access);
192 
193 	/* Obtain new slot. */
194 	if((g = cpf_new_grantslot()) < 0)
195 		return -1;
196 
197 	/* Basic sanity checks. */
198 	assert(GRANT_VALID(g));
199 	assert(g >= 0);
200 	assert(g < ngrants);
201 	assert(!(grants[g].cp_flags & CPF_USED));
202 
203 	if((r=cpf_setgrant_magic(g, who_to, who_from, addr,
204 		bytes, access)) < 0) {
205 		cpf_revoke(g);
206 		return -1;
207 	}
208 
209 	return g;
210 }
211 
212 int
213 cpf_revoke(cp_grant_id_t g)
214 {
215 /* Revoke previously granted access, identified by grant id. */
216 	GID_CHECK_USED(g);
217 
218 	/* Make grant invalid by setting flags to 0, clearing CPF_USED.
219 	 * This invalidates the grant.
220 	 */
221 	grants[g].cp_flags = 0;
222 
223 	return 0;
224 }
225 
226 int
227 cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee)
228 {
229 	/* First check slot validity, and if it's in use currently. */
230 	GID_CHECK_USED(g);
231 
232 	if(grants[g].cp_flags & CPF_DIRECT) {
233 		if(granter) *granter = SELF;
234 		if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to;
235 	} else if(grants[g].cp_flags & CPF_MAGIC) {
236 		if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from;
237 		if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to;
238 	} else	return -1;
239 
240 	return 0;
241 }
242 
243 int
244 cpf_getgrants(cp_grant_id_t *grant_ids, int n)
245 {
246 	int i;
247 
248 	for(i = 0; i < n; i++) {
249 	  if((grant_ids[i] = cpf_new_grantslot()) < 0)
250 		break;
251 	  grants[grant_ids[i]].cp_flags = CPF_USED;
252 	}
253 
254 	/* return however many grants were assigned. */
255 	return i;
256 }
257 
258 int
259 cpf_setgrant_direct(gid, who, addr, bytes, access)
260 cp_grant_id_t gid;
261 endpoint_t who;
262 vir_bytes addr;
263 size_t bytes;
264 int access;
265 {
266 	GID_CHECK(gid);
267 	ACCESS_CHECK(access);
268 
269 	/* Fill in new slot data. */
270 	grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
271 	grants[gid].cp_u.cp_direct.cp_who_to = who;
272 	grants[gid].cp_u.cp_direct.cp_start = addr;
273 	grants[gid].cp_u.cp_direct.cp_len = bytes;
274 
275 	return 0;
276 }
277 
278 int
279 cpf_setgrant_indirect(gid, who_to, who_from, his_gid)
280 cp_grant_id_t gid;
281 endpoint_t who_to, who_from;
282 cp_grant_id_t his_gid;
283 {
284 	GID_CHECK(gid);
285 
286 	/* Fill in new slot data. */
287 	grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID;
288 	grants[gid].cp_u.cp_indirect.cp_who_to = who_to;
289 	grants[gid].cp_u.cp_indirect.cp_who_from = who_from;
290 	grants[gid].cp_u.cp_indirect.cp_grant = his_gid;
291 
292 	return 0;
293 }
294 
295 int
296 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access)
297 cp_grant_id_t gid;
298 endpoint_t who_to, who_from;
299 vir_bytes addr;
300 size_t bytes;
301 int access;
302 {
303 	GID_CHECK(gid);
304 	ACCESS_CHECK(access);
305 
306 	/* Fill in new slot data. */
307 	grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
308 	grants[gid].cp_u.cp_magic.cp_who_to = who_to;
309 	grants[gid].cp_u.cp_magic.cp_who_from = who_from;
310 	grants[gid].cp_u.cp_magic.cp_start = addr;
311 	grants[gid].cp_u.cp_magic.cp_len = bytes;
312 
313 	return 0;
314 }
315 
316 int
317 cpf_setgrant_disable(gid)
318 cp_grant_id_t gid;
319 {
320 	GID_CHECK(gid);
321 
322 	/* Grant is now no longer valid, but still in use. */
323 	grants[gid].cp_flags = CPF_USED;
324 
325 	return 0;
326 }
327 
328 void
329 cpf_reload(void)
330 {
331 /* Inform the kernel about the location of the grant table. This is needed
332  * after a fork.
333  */
334 	if (grants)
335 		sys_setgrant(grants, ngrants);	/* Do we need error checking? */
336 }
337 
338