minix/servers/vm/acl.c
David van Moolenbroek 78d707cd26 VM: support for shared call mask ACLs
The VM server now manages its call masks such that all user processes
share the same call mask. As a result, an update for the call mask of
any user process will apply to all user processes. This is similar to
the privilege infrastructure employed by the kernel, and may serve as
a template for similar fine-grained restrictions in other servers.

Concretely, this patch fixes the problem of "service edit init" not
applying the given VM call mask to user processes started from RC
scripts during system startup.

In addition, this patch makes RS set a proper VM call mask for each
recovery script it spawns.

Change-Id: I520a30d85a0d3f3502d2b158293a2258825358cf
2013-08-08 23:22:58 +02:00

120 lines
2.5 KiB
C

/* Call mask ACL management. */
#include <minix/drivers.h>
#include "proto.h"
#include "glo.h"
#include "util.h"
#define NO_ACL -1
#define USER_ACL 0
#define FIRST_SYS_ACL 1
static bitchunk_t acl_mask[NR_SYS_PROCS][VM_CALL_MASK_SIZE];
static bitchunk_t acl_inuse[BITMAP_CHUNKS(NR_SYS_PROCS)];
/*
* Initialize ACL data structures.
*/
void
acl_init(void)
{
int i;
for (i = 0; i < ELEMENTS(vmproc); i++)
vmproc[i].vm_acl = NO_ACL;
memset(acl_mask, 0, sizeof(acl_mask));
memset(acl_inuse, 0, sizeof(acl_inuse));
}
/*
* Check whether a process is allowed to make a certain (zero-based) call.
* Return OK or an error.
*/
int
acl_check(struct vmproc *vmp, int call)
{
/* If the process has no ACL, all calls are allowed.. for now. */
if (vmp->vm_acl == NO_ACL) {
printf("VM: calling process %u has no ACL!\n",
vmp->vm_endpoint);
return OK;
}
/* See if the call is allowed. */
if (!GET_BIT(acl_mask[vmp->vm_acl], call))
return EPERM;
return OK;
}
/*
* Assign a call mask to a process. User processes share the first ACL entry.
* System processes are assigned to any of the other slots. For user
* processes, no call mask need to be provided: it will simply be inherited in
* that case.
*/
void
acl_set(struct vmproc *vmp, bitchunk_t *mask, int sys_proc)
{
int i;
acl_clear(vmp);
if (sys_proc) {
for (i = FIRST_SYS_ACL; i < NR_SYS_PROCS; i++)
if (!GET_BIT(acl_inuse, i))
break;
/*
* This should never happen. If it does, then different user
* processes have been assigned call masks separately. It is
* RS's responsibility to prevent that.
*/
if (i == NR_SYS_PROCS) {
printf("VM: no ACL entries available!\n");
return;
}
} else
i = USER_ACL;
if (!GET_BIT(acl_inuse, i) && mask == NULL)
printf("VM: WARNING: inheriting uninitialized ACL mask\n");
SET_BIT(acl_inuse, i);
vmp->vm_acl = i;
if (mask != NULL)
memcpy(&acl_mask[vmp->vm_acl], mask, sizeof(acl_mask[0]));
}
/*
* A process has forked. User processes inherit their parent's ACL by default,
* although they may be turned into system processes later. System processes
* do not inherit an ACL, and will have to be assigned one before getting to
* run.
*/
void
acl_fork(struct vmproc *vmp)
{
if (vmp->vm_acl != USER_ACL)
vmp->vm_acl = NO_ACL;
}
/*
* A process has exited. Decrease the reference count on its ACL entry, and
* mark the process as having no ACL.
*/
void
acl_clear(struct vmproc *vmp)
{
if (vmp->vm_acl != NO_ACL) {
if (vmp->vm_acl != USER_ACL)
UNSET_BIT(acl_inuse, vmp->vm_acl);
vmp->vm_acl = NO_ACL;
}
}