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