xref: /minix3/minix/servers/vm/acl.c (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
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 		printf("VM: calling process %u has no ACL!\n",
47 		    vmp->vm_endpoint);
48 
49 		return OK;
50 	}
51 
52 	/* See if the call is allowed. */
53 	if (!GET_BIT(acl_mask[vmp->vm_acl], call))
54 		return EPERM;
55 
56 	return OK;
57 }
58 
59 /*
60  * Assign a call mask to a process.  User processes share the first ACL entry.
61  * System processes are assigned to any of the other slots.  For user
62  * processes, no call mask need to be provided: it will simply be inherited in
63  * that case.
64  */
65 void
66 acl_set(struct vmproc *vmp, bitchunk_t *mask, int sys_proc)
67 {
68 	int i;
69 
70 	acl_clear(vmp);
71 
72 	if (sys_proc) {
73 		for (i = FIRST_SYS_ACL; i < NR_SYS_PROCS; i++)
74 			if (!GET_BIT(acl_inuse, i))
75 				break;
76 
77 		/*
78 		 * This should never happen.  If it does, then different user
79 		 * processes have been assigned call masks separately.  It is
80 		 * RS's responsibility to prevent that.
81 		 */
82 		if (i == NR_SYS_PROCS) {
83 			printf("VM: no ACL entries available!\n");
84 			return;
85 		}
86 	} else
87 		i = USER_ACL;
88 
89 	if (!GET_BIT(acl_inuse, i) && mask == NULL)
90 		printf("VM: WARNING: inheriting uninitialized ACL mask\n");
91 
92 	SET_BIT(acl_inuse, i);
93 	vmp->vm_acl = i;
94 
95 	if (mask != NULL)
96 		memcpy(&acl_mask[vmp->vm_acl], mask, sizeof(acl_mask[0]));
97 }
98 
99 /*
100  * A process has forked.  User processes inherit their parent's ACL by default,
101  * although they may be turned into system processes later.  System processes
102  * do not inherit an ACL, and will have to be assigned one before getting to
103  * run.
104  */
105 void
106 acl_fork(struct vmproc *vmp)
107 {
108 	if (vmp->vm_acl != USER_ACL)
109 		vmp->vm_acl = NO_ACL;
110 }
111 
112 /*
113  * A process has exited.  Decrease the reference count on its ACL entry, and
114  * mark the process as having no ACL.
115  */
116 void
117 acl_clear(struct vmproc *vmp)
118 {
119 	if (vmp->vm_acl != NO_ACL) {
120 		if (vmp->vm_acl != USER_ACL)
121 			UNSET_BIT(acl_inuse, vmp->vm_acl);
122 
123 		vmp->vm_acl = NO_ACL;
124 	}
125 }
126