make vfs & filesystems use failable copying
[minix3.git] / kernel / system / do_privctl.c
blob8b7dba019a583c9f6c0b2dc8f9919fe65547eabc
1 /* The kernel call implemented in this file:
2 * m_type: SYS_PRIVCTL
4 * The parameters for this kernel call are:
5 * m2_i1: CTL_ENDPT (process endpoint of target)
6 * m2_i2: CTL_REQUEST (privilege control request)
7 * m2_p1: CTL_ARG_PTR (pointer to request data)
8 */
10 #include "kernel/system.h"
11 #include "kernel/ipc.h"
12 #include <signal.h>
13 #include <string.h>
14 #include <minix/endpoint.h>
16 #if USE_PRIVCTL
18 #define PRIV_DEBUG 0
20 static int update_priv(struct proc *rp, struct priv *priv);
22 /*===========================================================================*
23 * do_privctl *
24 *===========================================================================*/
25 int do_privctl(struct proc * caller, message * m_ptr)
27 /* Handle sys_privctl(). Update a process' privileges. If the process is not
28 * yet a system process, make sure it gets its own privilege structure.
30 struct proc *rp;
31 proc_nr_t proc_nr;
32 sys_id_t priv_id;
33 sys_map_t map;
34 int ipc_to_m, kcalls;
35 int i, r;
36 struct io_range io_range;
37 struct minix_mem_range mem_range;
38 struct priv priv;
39 int irq;
41 /* Check whether caller is allowed to make this call. Privileged processes
42 * can only update the privileges of processes that are inhibited from
43 * running by the RTS_NO_PRIV flag. This flag is set when a privileged process
44 * forks.
46 if (! (priv(caller)->s_flags & SYS_PROC)) return(EPERM);
47 if(m_ptr->CTL_ENDPT == SELF) okendpt(caller->p_endpoint, &proc_nr);
48 else if(!isokendpt(m_ptr->CTL_ENDPT, &proc_nr)) return(EINVAL);
49 rp = proc_addr(proc_nr);
51 switch(m_ptr->CTL_REQUEST)
53 case SYS_PRIV_ALLOW:
54 /* Allow process to run. Make sure its privilege structure has already
55 * been set.
57 if (!RTS_ISSET(rp, RTS_NO_PRIV) || priv(rp)->s_proc_nr == NONE) {
58 return(EPERM);
60 RTS_UNSET(rp, RTS_NO_PRIV);
61 return(OK);
63 case SYS_PRIV_YIELD:
64 /* Allow process to run and suspend the caller. */
65 if (!RTS_ISSET(rp, RTS_NO_PRIV) || priv(rp)->s_proc_nr == NONE) {
66 return(EPERM);
68 RTS_SET(caller, RTS_NO_PRIV);
69 RTS_UNSET(rp, RTS_NO_PRIV);
70 return(OK);
72 case SYS_PRIV_DISALLOW:
73 /* Disallow process from running. */
74 if (RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM);
75 RTS_SET(rp, RTS_NO_PRIV);
76 return(OK);
78 case SYS_PRIV_SET_SYS:
79 /* Set a privilege structure of a blocked system process. */
80 if (! RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM);
82 /* Check whether a static or dynamic privilege id must be allocated. */
83 priv_id = NULL_PRIV_ID;
84 if (m_ptr->CTL_ARG_PTR)
86 /* Copy privilege structure from caller */
87 if((r=data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
88 KERNEL, (vir_bytes) &priv, sizeof(priv))) != OK)
89 return r;
91 /* See if the caller wants to assign a static privilege id. */
92 if(!(priv.s_flags & DYN_PRIV_ID)) {
93 priv_id = priv.s_id;
97 /* Make sure this process has its own privileges structure. This may
98 * fail, since there are only a limited number of system processes.
99 * Then copy privileges from the caller and restore some defaults.
101 if ((i=get_priv(rp, priv_id)) != OK)
103 printf("do_privctl: unable to allocate priv_id %d: %d\n",
104 priv_id, i);
105 return(i);
107 priv_id = priv(rp)->s_id; /* backup privilege id */
108 *priv(rp) = *priv(caller); /* copy from caller */
109 priv(rp)->s_id = priv_id; /* restore privilege id */
110 priv(rp)->s_proc_nr = proc_nr; /* reassociate process nr */
112 for (i=0; i< NR_SYS_CHUNKS; i++) /* remove pending: */
113 priv(rp)->s_notify_pending.chunk[i] = 0; /* - notifications */
114 priv(rp)->s_int_pending = 0; /* - interrupts */
115 (void) sigemptyset(&priv(rp)->s_sig_pending); /* - signals */
116 reset_kernel_timer(&priv(rp)->s_alarm_timer); /* - alarm */
117 priv(rp)->s_asyntab= -1; /* - asynsends */
118 priv(rp)->s_asynsize= 0;
119 priv(rp)->s_diag_sig = FALSE; /* no request for diag sigs */
121 /* Set defaults for privilege bitmaps. */
122 priv(rp)->s_flags= DSRV_F; /* privilege flags */
123 priv(rp)->s_trap_mask= DSRV_T; /* allowed traps */
124 memset(&map, 0, sizeof(map));
125 ipc_to_m = DSRV_M; /* allowed targets */
126 if (ipc_to_m == ALL_M) {
127 for (i = 0; i < NR_SYS_PROCS; i++)
128 set_sys_bit(map, i);
130 fill_sendto_mask(rp, &map);
131 kcalls = DSRV_KC; /* allowed kernel calls */
132 for(i = 0; i < SYS_CALL_MASK_SIZE; i++) {
133 priv(rp)->s_k_call_mask[i] = (kcalls == NO_C ? 0 : (~0));
136 /* Set the default signal managers. */
137 priv(rp)->s_sig_mgr = DSRV_SM;
138 priv(rp)->s_bak_sig_mgr = NONE;
140 /* Set defaults for resources: no I/O resources, no memory resources,
141 * no IRQs, no grant table
143 priv(rp)->s_nr_io_range= 0;
144 priv(rp)->s_nr_mem_range= 0;
145 priv(rp)->s_nr_irq= 0;
146 priv(rp)->s_grant_table= 0;
147 priv(rp)->s_grant_entries= 0;
149 /* Override defaults if the caller has supplied a privilege structure. */
150 if (m_ptr->CTL_ARG_PTR)
152 if((r = update_priv(rp, &priv)) != OK) {
153 return r;
157 return(OK);
159 case SYS_PRIV_SET_USER:
160 /* Set a privilege structure of a blocked user process. */
161 if (!RTS_ISSET(rp, RTS_NO_PRIV)) return(EPERM);
163 /* Link the process to the privilege structure of the root user
164 * process all the user processes share.
166 priv(rp) = priv_addr(USER_PRIV_ID);
168 return(OK);
170 case SYS_PRIV_ADD_IO:
171 if (RTS_ISSET(rp, RTS_NO_PRIV))
172 return(EPERM);
174 /* Only system processes get I/O resources? */
175 if (!(priv(rp)->s_flags & SYS_PROC))
176 return EPERM;
178 #if 0 /* XXX -- do we need a call for this? */
179 if (strcmp(rp->p_name, "fxp") == 0 ||
180 strcmp(rp->p_name, "rtl8139") == 0)
182 printf("setting ipc_stats_target to %d\n", rp->p_endpoint);
183 ipc_stats_target= rp->p_endpoint;
185 #endif
187 /* Get the I/O range */
188 data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
189 KERNEL, (vir_bytes) &io_range, sizeof(io_range));
190 priv(rp)->s_flags |= CHECK_IO_PORT; /* Check I/O accesses */
192 for (i = 0; i < priv(rp)->s_nr_io_range; i++) {
193 if (priv(rp)->s_io_tab[i].ior_base == io_range.ior_base &&
194 priv(rp)->s_io_tab[i].ior_limit == io_range.ior_limit)
195 return OK;
198 i= priv(rp)->s_nr_io_range;
199 if (i >= NR_IO_RANGE) {
200 printf("do_privctl: %d already has %d i/o ranges.\n",
201 rp->p_endpoint, i);
202 return ENOMEM;
205 priv(rp)->s_io_tab[i].ior_base= io_range.ior_base;
206 priv(rp)->s_io_tab[i].ior_limit= io_range.ior_limit;
207 priv(rp)->s_nr_io_range++;
209 return OK;
211 case SYS_PRIV_ADD_MEM:
212 if (RTS_ISSET(rp, RTS_NO_PRIV))
213 return(EPERM);
215 /* Only system processes get memory resources? */
216 if (!(priv(rp)->s_flags & SYS_PROC))
217 return EPERM;
219 /* Get the memory range */
220 if((r=data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
221 KERNEL, (vir_bytes) &mem_range, sizeof(mem_range))) != OK)
222 return r;
223 priv(rp)->s_flags |= CHECK_MEM; /* Check memory mappings */
225 /* When restarting a driver, check if it already has the permission */
226 for (i = 0; i < priv(rp)->s_nr_mem_range; i++) {
227 if (priv(rp)->s_mem_tab[i].mr_base == mem_range.mr_base &&
228 priv(rp)->s_mem_tab[i].mr_limit == mem_range.mr_limit)
229 return OK;
232 i= priv(rp)->s_nr_mem_range;
233 if (i >= NR_MEM_RANGE) {
234 printf("do_privctl: %d already has %d mem ranges.\n",
235 rp->p_endpoint, i);
236 return ENOMEM;
239 priv(rp)->s_mem_tab[i].mr_base= mem_range.mr_base;
240 priv(rp)->s_mem_tab[i].mr_limit= mem_range.mr_limit;
241 priv(rp)->s_nr_mem_range++;
243 return OK;
245 case SYS_PRIV_ADD_IRQ:
246 if (RTS_ISSET(rp, RTS_NO_PRIV))
247 return(EPERM);
249 /* Only system processes get IRQs? */
250 if (!(priv(rp)->s_flags & SYS_PROC))
251 return EPERM;
253 data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
254 KERNEL, (vir_bytes) &irq, sizeof(irq));
255 priv(rp)->s_flags |= CHECK_IRQ; /* Check IRQs */
257 /* When restarting a driver, check if it already has the permission */
258 for (i = 0; i < priv(rp)->s_nr_irq; i++) {
259 if (priv(rp)->s_irq_tab[i] == irq)
260 return OK;
263 i= priv(rp)->s_nr_irq;
264 if (i >= NR_IRQ) {
265 printf("do_privctl: %d already has %d irq's.\n",
266 rp->p_endpoint, i);
267 return ENOMEM;
269 priv(rp)->s_irq_tab[i]= irq;
270 priv(rp)->s_nr_irq++;
272 return OK;
273 case SYS_PRIV_QUERY_MEM:
275 phys_bytes addr, limit;
276 struct priv *sp;
277 /* See if a certain process is allowed to map in certain physical
278 * memory.
280 addr = (phys_bytes) m_ptr->CTL_PHYSSTART;
281 limit = addr + (phys_bytes) m_ptr->CTL_PHYSLEN - 1;
282 if(limit < addr)
283 return EPERM;
284 if(!(sp = priv(rp)))
285 return EPERM;
286 if (!(sp->s_flags & SYS_PROC))
287 return EPERM;
288 for(i = 0; i < sp->s_nr_mem_range; i++) {
289 if(addr >= sp->s_mem_tab[i].mr_base &&
290 limit <= sp->s_mem_tab[i].mr_limit)
291 return OK;
293 return EPERM;
296 case SYS_PRIV_UPDATE_SYS:
297 /* Update the privilege structure of a system process. */
298 if(!m_ptr->CTL_ARG_PTR) return EINVAL;
300 /* Copy privilege structure from caller */
301 if((r=data_copy(caller->p_endpoint, (vir_bytes) m_ptr->CTL_ARG_PTR,
302 KERNEL, (vir_bytes) &priv, sizeof(priv))) != OK)
303 return r;
305 /* Override settings in existing privilege structure. */
306 if((r = update_priv(rp, &priv)) != OK) {
307 return r;
310 return(OK);
312 default:
313 printf("do_privctl: bad request %d\n", m_ptr->CTL_REQUEST);
314 return EINVAL;
318 /*===========================================================================*
319 * update_priv *
320 *===========================================================================*/
321 static int update_priv(struct proc *rp, struct priv *priv)
323 /* Update the privilege structure of a given process. */
325 int i;
327 /* Copy s_flags and signal managers. */
328 priv(rp)->s_flags = priv->s_flags;
329 priv(rp)->s_sig_mgr = priv->s_sig_mgr;
330 priv(rp)->s_bak_sig_mgr = priv->s_bak_sig_mgr;
332 /* Copy IRQs. */
333 if(priv->s_flags & CHECK_IRQ) {
334 if (priv->s_nr_irq < 0 || priv->s_nr_irq > NR_IRQ)
335 return EINVAL;
336 priv(rp)->s_nr_irq= priv->s_nr_irq;
337 for (i= 0; i<priv->s_nr_irq; i++)
339 priv(rp)->s_irq_tab[i]= priv->s_irq_tab[i];
340 #if PRIV_DEBUG
341 printf("do_privctl: adding IRQ %d for %d\n",
342 priv(rp)->s_irq_tab[i], rp->p_endpoint);
343 #endif
347 /* Copy I/O ranges. */
348 if(priv->s_flags & CHECK_IO_PORT) {
349 if (priv->s_nr_io_range < 0 || priv->s_nr_io_range > NR_IO_RANGE)
350 return EINVAL;
351 priv(rp)->s_nr_io_range= priv->s_nr_io_range;
352 for (i= 0; i<priv->s_nr_io_range; i++)
354 priv(rp)->s_io_tab[i]= priv->s_io_tab[i];
355 #if PRIV_DEBUG
356 printf("do_privctl: adding I/O range [%x..%x] for %d\n",
357 priv(rp)->s_io_tab[i].ior_base,
358 priv(rp)->s_io_tab[i].ior_limit,
359 rp->p_endpoint);
360 #endif
364 /* Copy memory ranges. */
365 if(priv->s_flags & CHECK_MEM) {
366 if (priv->s_nr_mem_range < 0 || priv->s_nr_mem_range > NR_MEM_RANGE)
367 return EINVAL;
368 priv(rp)->s_nr_mem_range= priv->s_nr_mem_range;
369 for (i= 0; i<priv->s_nr_mem_range; i++)
371 priv(rp)->s_mem_tab[i]= priv->s_mem_tab[i];
372 #if PRIV_DEBUG
373 printf("do_privctl: adding mem range [%x..%x] for %d\n",
374 priv(rp)->s_mem_tab[i].mr_base,
375 priv(rp)->s_mem_tab[i].mr_limit,
376 rp->p_endpoint);
377 #endif
381 /* Copy trap mask. */
382 priv(rp)->s_trap_mask = priv->s_trap_mask;
384 /* Copy target mask. */
385 #if PRIV_DEBUG
386 printf("do_privctl: Setting ipc target mask for %d:");
387 for (i=0; i < NR_SYS_PROCS; i += BITCHUNK_BITS) {
388 printf(" %08x", get_sys_bits(priv->s_ipc_to, i));
390 printf("\n");
391 #endif
393 fill_sendto_mask(rp, &priv->s_ipc_to);
395 #if PRIV_DEBUG
396 printf("do_privctl: Set ipc target mask for %d:");
397 for (i=0; i < NR_SYS_PROCS; i += BITCHUNK_BITS) {
398 printf(" %08x", get_sys_bits(priv(rp)->s_ipc_to, i));
400 printf("\n");
401 #endif
403 /* Copy kernel call mask. */
404 memcpy(priv(rp)->s_k_call_mask, priv->s_k_call_mask,
405 sizeof(priv(rp)->s_k_call_mask));
407 return OK;
410 #endif /* USE_PRIVCTL */