|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Class and permission mappings.
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
#include <errno.h>
|
|
Packit |
3feee0 |
#include <stdio.h>
|
|
Packit |
3feee0 |
#include <stdlib.h>
|
|
Packit |
3feee0 |
#include <stdarg.h>
|
|
Packit |
3feee0 |
#include <stdbool.h>
|
|
Packit |
3feee0 |
#include <selinux/selinux.h>
|
|
Packit |
3feee0 |
#include <selinux/avc.h>
|
|
Packit |
3feee0 |
#include "callbacks.h"
|
|
Packit |
3feee0 |
#include "mapping.h"
|
|
Packit |
3feee0 |
#include "selinux_internal.h"
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Class and permission mappings
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
struct selinux_mapping {
|
|
Packit |
3feee0 |
security_class_t value; /* real, kernel value */
|
|
Packit |
3feee0 |
unsigned num_perms;
|
|
Packit |
3feee0 |
access_vector_t perms[sizeof(access_vector_t) * 8];
|
|
Packit |
3feee0 |
};
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
static struct selinux_mapping *current_mapping = NULL;
|
|
Packit |
3feee0 |
static security_class_t current_mapping_size = 0;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Mapping setting function
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
int
|
|
Packit |
3feee0 |
selinux_set_mapping(struct security_class_mapping *map)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
size_t size = sizeof(struct selinux_mapping);
|
|
Packit |
3feee0 |
security_class_t i, j;
|
|
Packit |
3feee0 |
unsigned k;
|
|
Packit |
3feee0 |
bool print_unknown_handle = false;
|
|
Packit |
3feee0 |
bool reject = (security_reject_unknown() == 1);
|
|
Packit |
3feee0 |
bool deny = (security_deny_unknown() == 1);
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
free(current_mapping);
|
|
Packit |
3feee0 |
current_mapping = NULL;
|
|
Packit |
3feee0 |
current_mapping_size = 0;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
if (avc_reset() < 0)
|
|
Packit |
3feee0 |
goto err;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* Find number of classes in the input mapping */
|
|
Packit |
3feee0 |
if (!map) {
|
|
Packit |
3feee0 |
errno = EINVAL;
|
|
Packit |
3feee0 |
goto err;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
i = 0;
|
|
Packit |
3feee0 |
while (map[i].name)
|
|
Packit |
3feee0 |
i++;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* Allocate space for the class records, plus one for class zero */
|
|
Packit |
3feee0 |
current_mapping = (struct selinux_mapping *)calloc(++i, size);
|
|
Packit |
3feee0 |
if (!current_mapping)
|
|
Packit |
3feee0 |
goto err;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* Store the raw class and permission values */
|
|
Packit |
3feee0 |
j = 0;
|
|
Packit |
3feee0 |
while (map[j].name) {
|
|
Packit |
3feee0 |
struct security_class_mapping *p_in = map + (j++);
|
|
Packit |
3feee0 |
struct selinux_mapping *p_out = current_mapping + j;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
p_out->value = string_to_security_class(p_in->name);
|
|
Packit |
3feee0 |
if (!p_out->value) {
|
|
Packit |
3feee0 |
selinux_log(SELINUX_INFO,
|
|
Packit |
3feee0 |
"SELinux: Class %s not defined in policy.\n",
|
|
Packit |
3feee0 |
p_in->name);
|
|
Packit |
3feee0 |
if (reject)
|
|
Packit |
3feee0 |
goto err2;
|
|
Packit |
3feee0 |
p_out->num_perms = 0;
|
|
Packit |
3feee0 |
print_unknown_handle = true;
|
|
Packit |
3feee0 |
continue;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
k = 0;
|
|
Packit |
3feee0 |
while (p_in->perms[k]) {
|
|
Packit |
3feee0 |
/* An empty permission string skips ahead */
|
|
Packit |
3feee0 |
if (!*p_in->perms[k]) {
|
|
Packit |
3feee0 |
k++;
|
|
Packit |
3feee0 |
continue;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
p_out->perms[k] = string_to_av_perm(p_out->value,
|
|
Packit |
3feee0 |
p_in->perms[k]);
|
|
Packit |
3feee0 |
if (!p_out->perms[k]) {
|
|
Packit |
3feee0 |
selinux_log(SELINUX_INFO,
|
|
Packit |
3feee0 |
"SELinux: Permission %s in class %s not defined in policy.\n",
|
|
Packit |
3feee0 |
p_in->perms[k], p_in->name);
|
|
Packit |
3feee0 |
if (reject)
|
|
Packit |
3feee0 |
goto err2;
|
|
Packit |
3feee0 |
print_unknown_handle = true;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
k++;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
p_out->num_perms = k;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
if (print_unknown_handle)
|
|
Packit |
3feee0 |
selinux_log(SELINUX_INFO,
|
|
Packit |
3feee0 |
"SELinux: the above unknown classes and permissions will be %s\n",
|
|
Packit |
3feee0 |
deny ? "denied" : "allowed");
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* Set the mapping size here so the above lookups are "raw" */
|
|
Packit |
3feee0 |
current_mapping_size = i;
|
|
Packit |
3feee0 |
return 0;
|
|
Packit |
3feee0 |
err2:
|
|
Packit |
3feee0 |
free(current_mapping);
|
|
Packit |
3feee0 |
current_mapping = NULL;
|
|
Packit |
3feee0 |
current_mapping_size = 0;
|
|
Packit |
3feee0 |
err:
|
|
Packit |
3feee0 |
return -1;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Get real, kernel values from mapped values
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
security_class_t
|
|
Packit |
3feee0 |
unmap_class(security_class_t tclass)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
if (tclass < current_mapping_size)
|
|
Packit |
3feee0 |
return current_mapping[tclass].value;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* If here no mapping set or the class requested is not valid. */
|
|
Packit |
3feee0 |
if (current_mapping_size != 0) {
|
|
Packit |
3feee0 |
errno = EINVAL;
|
|
Packit |
3feee0 |
return 0;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
else
|
|
Packit |
3feee0 |
return tclass;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
access_vector_t
|
|
Packit |
3feee0 |
unmap_perm(security_class_t tclass, access_vector_t tperm)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
if (tclass < current_mapping_size) {
|
|
Packit |
3feee0 |
unsigned i;
|
|
Packit |
3feee0 |
access_vector_t kperm = 0;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i=0; i
|
|
Packit |
3feee0 |
if (tperm & (1<
|
|
Packit |
3feee0 |
kperm |= current_mapping[tclass].perms[i];
|
|
Packit |
3feee0 |
tperm &= ~(1<
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
return kperm;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* If here no mapping set or the perm requested is not valid. */
|
|
Packit |
3feee0 |
if (current_mapping_size != 0) {
|
|
Packit |
3feee0 |
errno = EINVAL;
|
|
Packit |
3feee0 |
return 0;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
else
|
|
Packit |
3feee0 |
return tperm;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Get mapped values from real, kernel values
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
security_class_t
|
|
Packit |
3feee0 |
map_class(security_class_t kclass)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
security_class_t i;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i=0; i
|
|
Packit |
3feee0 |
if (current_mapping[i].value == kclass)
|
|
Packit |
3feee0 |
return i;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/* If here no mapping set or the class requested is not valid. */
|
|
Packit |
3feee0 |
if (current_mapping_size != 0) {
|
|
Packit |
3feee0 |
errno = EINVAL;
|
|
Packit |
3feee0 |
return 0;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
else
|
|
Packit |
3feee0 |
return kclass;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
access_vector_t
|
|
Packit |
3feee0 |
map_perm(security_class_t tclass, access_vector_t kperm)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
if (tclass < current_mapping_size) {
|
|
Packit |
3feee0 |
unsigned i;
|
|
Packit |
3feee0 |
access_vector_t tperm = 0;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i=0; i
|
|
Packit |
3feee0 |
if (kperm & current_mapping[tclass].perms[i]) {
|
|
Packit |
3feee0 |
tperm |= 1<
|
|
Packit |
3feee0 |
kperm &= ~current_mapping[tclass].perms[i];
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
if (tperm == 0) {
|
|
Packit |
3feee0 |
errno = EINVAL;
|
|
Packit |
3feee0 |
return 0;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
else
|
|
Packit |
3feee0 |
return tperm;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
return kperm;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
void
|
|
Packit |
3feee0 |
map_decision(security_class_t tclass, struct av_decision *avd)
|
|
Packit |
3feee0 |
{
|
|
Packit |
3feee0 |
if (tclass < current_mapping_size) {
|
|
Packit |
3feee0 |
bool allow_unknown = (security_deny_unknown() == 0);
|
|
Packit |
3feee0 |
struct selinux_mapping *mapping = ¤t_mapping[tclass];
|
|
Packit |
3feee0 |
unsigned int i, n = mapping->num_perms;
|
|
Packit |
3feee0 |
access_vector_t result;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i = 0, result = 0; i < n; i++) {
|
|
Packit |
3feee0 |
if (avd->allowed & mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
else if (allow_unknown && !mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
avd->allowed = result;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i = 0, result = 0; i < n; i++) {
|
|
Packit |
3feee0 |
if (avd->decided & mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
else if (allow_unknown && !mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
avd->decided = result;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i = 0, result = 0; i < n; i++)
|
|
Packit |
3feee0 |
if (avd->auditallow & mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
avd->auditallow = result;
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
for (i = 0, result = 0; i < n; i++) {
|
|
Packit |
3feee0 |
if (avd->auditdeny & mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
else if (!allow_unknown && !mapping->perms[i])
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
|
|
Packit |
3feee0 |
/*
|
|
Packit |
3feee0 |
* Make sure we audit denials for any permission check
|
|
Packit |
3feee0 |
* beyond the mapping->num_perms since this indicates
|
|
Packit |
3feee0 |
* a bug in the object manager.
|
|
Packit |
3feee0 |
*/
|
|
Packit |
3feee0 |
for (; i < (sizeof(result)*8); i++)
|
|
Packit |
3feee0 |
result |= 1<
|
|
Packit |
3feee0 |
avd->auditdeny = result;
|
|
Packit |
3feee0 |
}
|
|
Packit |
3feee0 |
}
|