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