xref: /minix3/minix/servers/vm/acl.c (revision 65b4b95259c5be80f21ebbfbf258aa91c6ee12c5)
1433d6423SLionel Sambuc 
2433d6423SLionel Sambuc /* Call mask ACL management. */
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #include <minix/drivers.h>
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include "proto.h"
7433d6423SLionel Sambuc #include "glo.h"
8433d6423SLionel Sambuc #include "util.h"
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #define NO_ACL		-1
11433d6423SLionel Sambuc #define USER_ACL	 0
12433d6423SLionel Sambuc #define FIRST_SYS_ACL	 1
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc static bitchunk_t acl_mask[NR_SYS_PROCS][VM_CALL_MASK_SIZE];
15433d6423SLionel Sambuc static bitchunk_t acl_inuse[BITMAP_CHUNKS(NR_SYS_PROCS)];
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc /*
18433d6423SLionel Sambuc  * Initialize ACL data structures.
19433d6423SLionel Sambuc  */
20433d6423SLionel Sambuc void
21433d6423SLionel Sambuc acl_init(void)
22433d6423SLionel Sambuc {
23433d6423SLionel Sambuc 	int i;
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc 	for (i = 0; i < ELEMENTS(vmproc); i++)
26433d6423SLionel Sambuc 		vmproc[i].vm_acl = NO_ACL;
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc 	memset(acl_mask, 0, sizeof(acl_mask));
29433d6423SLionel Sambuc 	memset(acl_inuse, 0, sizeof(acl_inuse));
30433d6423SLionel Sambuc }
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc /*
33433d6423SLionel Sambuc  * Check whether a process is allowed to make a certain (zero-based) call.
34433d6423SLionel Sambuc  * Return OK or an error.
35433d6423SLionel Sambuc  */
36433d6423SLionel Sambuc int
37433d6423SLionel Sambuc acl_check(struct vmproc *vmp, int call)
38433d6423SLionel Sambuc {
39*65b4b952SCristiano Giuffrida 
40*65b4b952SCristiano Giuffrida 	/* VM makes asynchronous calls to itself.  Always allow those. */
41*65b4b952SCristiano Giuffrida 	if (vmp->vm_endpoint == VM_PROC_NR)
42*65b4b952SCristiano Giuffrida 		return OK;
43*65b4b952SCristiano Giuffrida 
44433d6423SLionel Sambuc 	/* If the process has no ACL, all calls are allowed.. for now. */
45433d6423SLionel Sambuc 	if (vmp->vm_acl == NO_ACL) {
46433d6423SLionel Sambuc 		printf("VM: calling process %u has no ACL!\n",
47433d6423SLionel Sambuc 		    vmp->vm_endpoint);
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc 		return OK;
50433d6423SLionel Sambuc 	}
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc 	/* See if the call is allowed. */
53433d6423SLionel Sambuc 	if (!GET_BIT(acl_mask[vmp->vm_acl], call))
54433d6423SLionel Sambuc 		return EPERM;
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc 	return OK;
57433d6423SLionel Sambuc }
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc /*
60433d6423SLionel Sambuc  * Assign a call mask to a process.  User processes share the first ACL entry.
61433d6423SLionel Sambuc  * System processes are assigned to any of the other slots.  For user
62433d6423SLionel Sambuc  * processes, no call mask need to be provided: it will simply be inherited in
63433d6423SLionel Sambuc  * that case.
64433d6423SLionel Sambuc  */
65433d6423SLionel Sambuc void
66433d6423SLionel Sambuc acl_set(struct vmproc *vmp, bitchunk_t *mask, int sys_proc)
67433d6423SLionel Sambuc {
68433d6423SLionel Sambuc 	int i;
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc 	acl_clear(vmp);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 	if (sys_proc) {
73433d6423SLionel Sambuc 		for (i = FIRST_SYS_ACL; i < NR_SYS_PROCS; i++)
74433d6423SLionel Sambuc 			if (!GET_BIT(acl_inuse, i))
75433d6423SLionel Sambuc 				break;
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc 		/*
78433d6423SLionel Sambuc 		 * This should never happen.  If it does, then different user
79433d6423SLionel Sambuc 		 * processes have been assigned call masks separately.  It is
80433d6423SLionel Sambuc 		 * RS's responsibility to prevent that.
81433d6423SLionel Sambuc 		 */
82433d6423SLionel Sambuc 		if (i == NR_SYS_PROCS) {
83433d6423SLionel Sambuc 			printf("VM: no ACL entries available!\n");
84433d6423SLionel Sambuc 			return;
85433d6423SLionel Sambuc 		}
86433d6423SLionel Sambuc 	} else
87433d6423SLionel Sambuc 		i = USER_ACL;
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 	if (!GET_BIT(acl_inuse, i) && mask == NULL)
90433d6423SLionel Sambuc 		printf("VM: WARNING: inheriting uninitialized ACL mask\n");
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	SET_BIT(acl_inuse, i);
93433d6423SLionel Sambuc 	vmp->vm_acl = i;
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 	if (mask != NULL)
96433d6423SLionel Sambuc 		memcpy(&acl_mask[vmp->vm_acl], mask, sizeof(acl_mask[0]));
97433d6423SLionel Sambuc }
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc /*
100433d6423SLionel Sambuc  * A process has forked.  User processes inherit their parent's ACL by default,
101433d6423SLionel Sambuc  * although they may be turned into system processes later.  System processes
102433d6423SLionel Sambuc  * do not inherit an ACL, and will have to be assigned one before getting to
103433d6423SLionel Sambuc  * run.
104433d6423SLionel Sambuc  */
105433d6423SLionel Sambuc void
106433d6423SLionel Sambuc acl_fork(struct vmproc *vmp)
107433d6423SLionel Sambuc {
108433d6423SLionel Sambuc 	if (vmp->vm_acl != USER_ACL)
109433d6423SLionel Sambuc 		vmp->vm_acl = NO_ACL;
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /*
113433d6423SLionel Sambuc  * A process has exited.  Decrease the reference count on its ACL entry, and
114433d6423SLionel Sambuc  * mark the process as having no ACL.
115433d6423SLionel Sambuc  */
116433d6423SLionel Sambuc void
117433d6423SLionel Sambuc acl_clear(struct vmproc *vmp)
118433d6423SLionel Sambuc {
119433d6423SLionel Sambuc 	if (vmp->vm_acl != NO_ACL) {
120433d6423SLionel Sambuc 		if (vmp->vm_acl != USER_ACL)
121433d6423SLionel Sambuc 			UNSET_BIT(acl_inuse, vmp->vm_acl);
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 		vmp->vm_acl = NO_ACL;
124433d6423SLionel Sambuc 	}
125433d6423SLionel Sambuc }
126