147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Class and permission mappings.
347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <errno.h>
647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdio.h>
747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdlib.h>
847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdarg.h>
947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <assert.h>
1047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <selinux/selinux.h>
1147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <selinux/avc.h>
1247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "mapping.h"
1347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
1447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
1547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Class and permission mappings
1647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
1747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
1847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstruct selinux_mapping {
1947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	security_class_t value; /* real, kernel value */
2047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned num_perms;
2147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	access_vector_t perms[sizeof(access_vector_t) * 8];
2247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner};
2347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct selinux_mapping *current_mapping = NULL;
2547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic security_class_t current_mapping_size = 0;
2647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
2847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Mapping setting function
2947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
3047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint
3247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerselinux_set_mapping(struct security_class_mapping *map)
3347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
3447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t size = sizeof(struct selinux_mapping);
3547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	security_class_t i, j;
3647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned k;
3747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(current_mapping);
3947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping = NULL;
4047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping_size = 0;
4147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (avc_reset() < 0)
4347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err;
4447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Find number of classes in the input mapping */
4647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!map) {
4747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = EINVAL;
4847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err;
4947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
5047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	i = 0;
5147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (map[i].name)
5247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		i++;
5347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Allocate space for the class records, plus one for class zero */
5547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping = (struct selinux_mapping *)calloc(++i, size);
5647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!current_mapping)
5747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto err;
5847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Store the raw class and permission values */
6047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	j = 0;
6147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (map[j].name) {
6247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct security_class_mapping *p_in = map + (j++);
6347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct selinux_mapping *p_out = current_mapping + j;
6447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		p_out->value = string_to_security_class(p_in->name);
6647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!p_out->value)
6747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto err2;
6847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		k = 0;
7047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		while (p_in->perms && p_in->perms[k]) {
7147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			/* An empty permission string skips ahead */
7247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (!*p_in->perms[k]) {
7347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				k++;
7447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				continue;
7547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
7647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			p_out->perms[k] = string_to_av_perm(p_out->value,
7747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner							    p_in->perms[k]);
7847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (!p_out->perms[k])
7947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto err2;
8047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			k++;
8147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
8247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		p_out->num_perms = k;
8347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
8447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Set the mapping size here so the above lookups are "raw" */
8647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping_size = i;
8747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
8847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr2:
8947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(current_mapping);
9047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping = NULL;
9147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	current_mapping_size = 0;
9247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnererr:
9347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return -1;
9447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
9547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
9747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Get real, kernel values from mapped values
9847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
9947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnersecurity_class_t
10147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerunmap_class(security_class_t tclass)
10247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
10347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (tclass < current_mapping_size)
10447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return current_mapping[tclass].value;
10547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	assert(current_mapping_size == 0);
10747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return tclass;
10847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
10947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turneraccess_vector_t
11147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerunmap_perm(security_class_t tclass, access_vector_t tperm)
11247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
11347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (tclass < current_mapping_size) {
11447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned i;
11547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		access_vector_t kperm = 0;
11647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0; i<current_mapping[tclass].num_perms; i++)
11847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (tperm & (1<<i)) {
11947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				assert(current_mapping[tclass].perms[i]);
12047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				kperm |= current_mapping[tclass].perms[i];
12147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				tperm &= ~(1<<i);
12247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
12347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		assert(tperm == 0);
12447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return kperm;
12547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
12647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	assert(current_mapping_size == 0);
12847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return tperm;
12947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
13047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
13247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Get mapped values from real, kernel values
13347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
13447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnersecurity_class_t
13647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnermap_class(security_class_t kclass)
13747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
13847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	security_class_t i;
13947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i=0; i<current_mapping_size; i++)
14147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (current_mapping[i].value == kclass)
14247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return i;
14347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	assert(current_mapping_size == 0);
14547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return kclass;
14647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
14747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turneraccess_vector_t
14947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnermap_perm(security_class_t tclass, access_vector_t kperm)
15047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
15147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (tclass < current_mapping_size) {
15247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned i;
15347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		access_vector_t tperm = 0;
15447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0; i<current_mapping[tclass].num_perms; i++)
15647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (kperm & current_mapping[tclass].perms[i]) {
15747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				tperm |= 1<<i;
15847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				kperm &= ~current_mapping[tclass].perms[i];
15947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
16047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		assert(kperm == 0);
16147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return tperm;
16247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
16347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	assert(current_mapping_size == 0);
16547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return kperm;
16647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
16747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid
16947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnermap_decision(security_class_t tclass, struct av_decision *avd)
17047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
17147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (tclass < current_mapping_size) {
17247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned i;
17347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		access_vector_t result;
17447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
17647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (avd->allowed & current_mapping[tclass].perms[i])
17747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				result |= 1<<i;
17847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avd->allowed = result;
17947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
18147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (avd->decided & current_mapping[tclass].perms[i])
18247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				result |= 1<<i;
18347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avd->decided = result;
18447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
18647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (avd->auditallow & current_mapping[tclass].perms[i])
18747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				result |= 1<<i;
18847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avd->auditallow = result;
18947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
19147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (avd->auditdeny & current_mapping[tclass].perms[i])
19247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				result |= 1<<i;
19347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avd->auditdeny = result;
19447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
19547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
196