xref: /minix/minix/servers/vm/acl.c (revision 0a6a1f1d)
1 
2 /* Call mask ACL management. */
3 
4 #include <minix/drivers.h>
5 
6 #include "proto.h"
7 #include "glo.h"
8 #include "util.h"
9 
10 #define NO_ACL		-1
11 #define USER_ACL	 0
12 #define FIRST_SYS_ACL	 1
13 
14 static bitchunk_t acl_mask[NR_SYS_PROCS][VM_CALL_MASK_SIZE];
15 static bitchunk_t acl_inuse[BITMAP_CHUNKS(NR_SYS_PROCS)];
16 
17 /*
18  * Initialize ACL data structures.
19  */
20 void
21 acl_init(void)
22 {
23 	int i;
24 
25 	for (i = 0; i < ELEMENTS(vmproc); i++)
26 		vmproc[i].vm_acl = NO_ACL;
27 
28 	memset(acl_mask, 0, sizeof(acl_mask));
29 	memset(acl_inuse, 0, sizeof(acl_inuse));
30 }
31 
32 /*
33  * Check whether a process is allowed to make a certain (zero-based) call.
34  * Return OK or an error.
35  */
36 int
37 acl_check(struct vmproc *vmp, int call)
38 {
39 
40 	/* VM makes asynchronous calls to itself.  Always allow those. */
41 	if (vmp->vm_endpoint == VM_PROC_NR)
42 		return OK;
43 
44 	/* If the process has no ACL, all calls are allowed.. for now. */
45 	if (vmp->vm_acl == NO_ACL) {
46 		/* RS instrumented with ASR may call VM_BRK at startup. */
47 		if (vmp->vm_endpoint == RS_PROC_NR)
48 			return OK;
49 
50 		printf("VM: calling process %u has no ACL!\n",
51 		    vmp->vm_endpoint);
52 
53 		return OK;
54 	}
55 
56 	/* See if the call is allowed. */
57 	if (!GET_BIT(acl_mask[vmp->vm_acl], call))
58 		return EPERM;
59 
60 	return OK;
61 }
62 
63 /*
64  * Assign a call mask to a process.  User processes share the first ACL entry.
65  * System processes are assigned to any of the other slots.  For user
66  * processes, no call mask need to be provided: it will simply be inherited in
67  * that case.
68  */
69 void
70 acl_set(struct vmproc *vmp, bitchunk_t *mask, int sys_proc)
71 {
72 	int i;
73 
74 	acl_clear(vmp);
75 
76 	if (sys_proc) {
77 		for (i = FIRST_SYS_ACL; i < NR_SYS_PROCS; i++)
78 			if (!GET_BIT(acl_inuse, i))
79 				break;
80 
81 		/*
82 		 * This should never happen.  If it does, then different user
83 		 * processes have been assigned call masks separately.  It is
84 		 * RS's responsibility to prevent that.
85 		 */
86 		if (i == NR_SYS_PROCS) {
87 			printf("VM: no ACL entries available!\n");
88 			return;
89 		}
90 	} else
91 		i = USER_ACL;
92 
93 	if (!GET_BIT(acl_inuse, i) && mask == NULL)
94 		printf("VM: WARNING: inheriting uninitialized ACL mask\n");
95 
96 	SET_BIT(acl_inuse, i);
97 	vmp->vm_acl = i;
98 
99 	if (mask != NULL)
100 		memcpy(&acl_mask[vmp->vm_acl], mask, sizeof(acl_mask[0]));
101 }
102 
103 /*
104  * A process has forked.  User processes inherit their parent's ACL by default,
105  * although they may be turned into system processes later.  System processes
106  * do not inherit an ACL, and will have to be assigned one before getting to
107  * run.
108  */
109 void
110 acl_fork(struct vmproc *vmp)
111 {
112 	if (vmp->vm_acl != USER_ACL)
113 		vmp->vm_acl = NO_ACL;
114 }
115 
116 /*
117  * A process has exited.  Decrease the reference count on its ACL entry, and
118  * mark the process as having no ACL.
119  */
120 void
121 acl_clear(struct vmproc *vmp)
122 {
123 	if (vmp->vm_acl != NO_ACL) {
124 		if (vmp->vm_acl != USER_ACL)
125 			UNSET_BIT(acl_inuse, vmp->vm_acl);
126 
127 		vmp->vm_acl = NO_ACL;
128 	}
129 }
130