3.1.7 branch.
[minix.git] / kernel / system / do_safemap.c
blob33649b76ec3faa492a207d3ddc88bb78ecc2e024
1 /* The kernel call implemented in this file:
2 * m_type: SYS_SAFEMAP or SYS_SAFEREVMAP or SYS_SAFEUNMAP
4 * The parameters for this kernel call are:
5 * SMAP_EP endpoint of the grantor
6 * SMAP_GID grant id
7 * SMAP_OFFSET offset of the grant space
8 * SMAP_SEG segment
9 * SMAP_ADDRESS address
10 * SMAP_BYTES bytes to be copied
11 * SMAP_FLAG access, writable map or not?
14 #include <assert.h>
16 #include <minix/type.h>
17 #include <minix/type.h>
18 #include <minix/safecopies.h>
20 #include "kernel/system.h"
22 #include <signal.h>
24 struct map_info_s {
25 int flag;
27 /* Grantor. */
28 endpoint_t grantor;
29 cp_grant_id_t gid;
30 vir_bytes offset;
31 vir_bytes address_Dseg; /* seg always is D */
33 /* Grantee. */
34 endpoint_t grantee;
35 int seg;
36 vir_bytes address;
38 /* Length. */
39 vir_bytes bytes;
42 #define MAX_MAP_INFO 20
43 static struct map_info_s map_info[MAX_MAP_INFO];
45 /*===========================================================================*
46 * add_info *
47 *===========================================================================*/
48 static int add_info(endpoint_t grantor, endpoint_t grantee, cp_grant_id_t gid,
49 vir_bytes offset, vir_bytes address_Dseg,
50 int seg, vir_bytes address, vir_bytes bytes)
52 int i;
54 for(i = 0; i < MAX_MAP_INFO; i++) {
55 if(map_info[i].flag == 0)
56 break;
58 if(i == MAX_MAP_INFO)
59 return EBUSY;
61 map_info[i].flag = 1;
62 map_info[i].grantor = grantor;
63 map_info[i].grantee = grantee;
64 map_info[i].gid = gid;
65 map_info[i].address_Dseg = address_Dseg;
66 map_info[i].offset = offset;
67 map_info[i].seg = seg;
68 map_info[i].address = address;
69 map_info[i].bytes = bytes;
71 return OK;
74 /*===========================================================================*
75 * get_revoke_info *
76 *===========================================================================*/
77 static struct map_info_s *get_revoke_info(endpoint_t grantor, int flag, int arg)
79 int i;
80 for(i = 0; i < MAX_MAP_INFO; i++) {
81 if(map_info[i].flag == 1
82 && map_info[i].grantor == grantor
83 && (flag ? (map_info[i].gid == arg)
84 : (map_info[i].address_Dseg == arg)))
85 return &map_info[i];
88 return NULL;
91 /*===========================================================================*
92 * get_unmap_info *
93 *===========================================================================*/
94 static struct map_info_s *get_unmap_info(endpoint_t grantee, int seg,
95 vir_bytes address)
97 int i;
98 for(i = 0; i < MAX_MAP_INFO; i++) {
99 if(map_info[i].flag == 1
100 && map_info[i].grantee == grantee
101 && map_info[i].seg == seg
102 && map_info[i].address == address)
103 return &map_info[i];
106 return NULL;
109 /*===========================================================================*
110 * clear_info *
111 *===========================================================================*/
112 static void clear_info(struct map_info_s *p)
114 p->flag = 0;
117 /*===========================================================================*
118 * map_invoke_vm *
119 *===========================================================================*/
120 PUBLIC int map_invoke_vm(struct proc * caller,
121 int req_type, /* VMPTYPE_... COWMAP, SMAP, SUNMAP */
122 endpoint_t end_d, int seg_d, vir_bytes off_d,
123 endpoint_t end_s, int seg_s, vir_bytes off_s,
124 size_t size, int flag)
126 struct proc *src, *dst;
127 phys_bytes lin_src, lin_dst;
129 src = endpoint_lookup(end_s);
130 dst = endpoint_lookup(end_d);
132 lin_src = umap_local(src, seg_s, off_s, size);
133 lin_dst = umap_local(dst, seg_d, off_d, size);
134 if(lin_src == 0 || lin_dst == 0) {
135 printf("map_invoke_vm: error in umap_local.\n");
136 return EINVAL;
139 /* Make sure the linear addresses are both page aligned. */
140 if(lin_src % CLICK_SIZE != 0
141 || lin_dst % CLICK_SIZE != 0) {
142 printf("map_invoke_vm: linear addresses not page aligned.\n");
143 return EINVAL;
146 assert(!RTS_ISSET(caller, RTS_VMREQUEST));
147 assert(!RTS_ISSET(caller, RTS_VMREQTARGET));
148 assert(!RTS_ISSET(dst, RTS_VMREQUEST));
149 assert(!RTS_ISSET(dst, RTS_VMREQTARGET));
150 RTS_SET(caller, RTS_VMREQUEST);
151 RTS_SET(dst, RTS_VMREQTARGET);
153 /* Map to the destination. */
154 caller->p_vmrequest.req_type = req_type;
155 caller->p_vmrequest.target = end_d; /* destination proc */
156 caller->p_vmrequest.params.map.vir_d = lin_dst; /* destination addr */
157 caller->p_vmrequest.params.map.ep_s = end_s; /* source process */
158 caller->p_vmrequest.params.map.vir_s = lin_src; /* source address */
159 caller->p_vmrequest.params.map.length = (vir_bytes) size;
160 caller->p_vmrequest.params.map.writeflag = flag;
162 caller->p_vmrequest.type = VMSTYPE_MAP;
164 /* Connect caller on vmrequest wait queue. */
165 if(!(caller->p_vmrequest.nextrequestor = vmrequest))
166 send_sig(VM_PROC_NR, SIGKMEM);
167 vmrequest = caller;
169 return OK;
172 /*===========================================================================*
173 * do_safemap *
174 *===========================================================================*/
175 PUBLIC int do_safemap(struct proc * caller, message * m_ptr)
177 endpoint_t grantor = m_ptr->SMAP_EP;
178 cp_grant_id_t gid = (cp_grant_id_t) m_ptr->SMAP_GID;
179 vir_bytes offset = (vir_bytes) m_ptr->SMAP_OFFSET;
180 int seg = (int) m_ptr->SMAP_SEG;
181 vir_bytes address = (vir_bytes) m_ptr->SMAP_ADDRESS;
182 vir_bytes bytes = (vir_bytes) m_ptr->SMAP_BYTES;
183 int flag = m_ptr->SMAP_FLAG;
185 vir_bytes offset_result;
186 endpoint_t new_grantor;
187 int r;
188 int access = CPF_MAP | CPF_READ;
190 /* Check the grant. We currently support safemap with both direct and
191 * indirect grants, as verify_grant() stores the original grantor
192 * transparently in new_grantor below. However, we maintain the original
193 * semantics associated to indirect grants only here at safemap time.
194 * After the mapping has been set up, if a process part of the chain
195 * of trust crashes or exits without revoking the mapping, the mapping
196 * can no longer be manually or automatically revoked for any of the
197 * processes lower in the chain. This solution reduces complexity but
198 * could be improved if we make the assumption that only one process in
199 * the chain of trust can effectively map the original memory region.
201 if(flag != 0)
202 access |= CPF_WRITE;
203 r = verify_grant(grantor, caller->p_endpoint, gid, bytes, access,
204 offset, &offset_result, &new_grantor);
205 if(r != OK) {
206 printf("verify_grant for gid %d from %d to %d failed: %d\n",
207 gid, grantor, caller->p_endpoint, r);
208 return r;
211 /* Add map info. */
212 r = add_info(new_grantor, caller->p_endpoint, gid, offset,
213 offset_result, seg, address, bytes);
214 if(r != OK)
215 return r;
217 /* Invoke VM. */
218 return map_invoke_vm(caller, VMPTYPE_SMAP,
219 caller->p_endpoint, seg, address, new_grantor, D, offset_result, bytes,flag);
222 /*===========================================================================*
223 * safeunmap *
224 *===========================================================================*/
225 PRIVATE int safeunmap(struct proc * caller, struct map_info_s *p)
227 vir_bytes offset_result;
228 endpoint_t new_grantor;
229 int r;
231 r = verify_grant(p->grantor, p->grantee, p->gid, p->bytes,
232 CPF_MAP, p->offset, &offset_result, &new_grantor);
233 if(r != OK) {
234 printf("safeunmap: error in verify_grant.\n");
235 return r;
238 r = map_invoke_vm(caller, VMPTYPE_SUNMAP,
239 p->grantee, p->seg, p->address,
240 new_grantor, D, offset_result,
241 p->bytes, 0);
242 clear_info(p);
243 if(r != OK) {
244 printf("safeunmap: error in map_invoke_vm.\n");
245 return r;
247 return OK;
250 /*===========================================================================*
251 * do_saferevmap *
252 *===========================================================================*/
253 PUBLIC int do_saferevmap(struct proc * caller, message * m_ptr)
255 struct map_info_s *p;
256 int flag = m_ptr->SMAP_FLAG;
257 int arg = m_ptr->SMAP_GID; /* gid or address_Dseg */
258 int r;
260 while((p = get_revoke_info(caller->p_endpoint, flag, arg)) != NULL) {
261 if((r = safeunmap(caller, p)) != OK)
262 return r;
264 return OK;
267 /*===========================================================================*
268 * do_safeunmap *
269 *===========================================================================*/
270 PUBLIC int do_safeunmap(struct proc * caller, message * m_ptr)
272 vir_bytes address = (vir_bytes) m_ptr->SMAP_ADDRESS;
273 int seg = (int)m_ptr->SMAP_SEG;
274 struct map_info_s *p;
275 int r;
277 while((p = get_unmap_info(caller->p_endpoint, seg, address)) != NULL) {
278 if((r = safeunmap(caller, p)) != OK)
279 return r;
281 return OK;