mirror of
https://github.com/SELinuxProject/selinux
synced 2025-03-08 03:07:33 +00:00
Neverallow rules for ioctl extended permissions will pass in two cases: 1. If extended permissions exist for the source-target-class set the test will pass if the neverallow values are excluded. 2. If extended permissions do not exist for the source-target-class set the test will pass if the ioctl permission is not granted. Signed-off-by: Jeff Vander Stoep <jeffv@google.com> Acked-by: Nick Kralevich <nnk@google.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
287 lines
7.1 KiB
C
287 lines
7.1 KiB
C
/* Authors: Joshua Brindle <jbrindle@tresys.com>
|
|
* Jason Tang <jtang@tresys.com>
|
|
*
|
|
* Copyright (C) 2005-2006 Tresys Technology, LLC
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <sepol/policydb/flask_types.h>
|
|
#include <sepol/policydb/policydb.h>
|
|
#include <sepol/policydb/util.h>
|
|
#include <dso.h>
|
|
|
|
struct val_to_name {
|
|
unsigned int val;
|
|
char *name;
|
|
};
|
|
|
|
/* Add an unsigned integer to a dynamically reallocated array. *cnt
|
|
* is a reference pointer to the number of values already within array
|
|
* *a; it will be incremented upon successfully appending i. If *a is
|
|
* NULL then this function will create a new array (*cnt is reset to
|
|
* 0). Return 0 on success, -1 on out of memory. */
|
|
int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
|
|
{
|
|
if (cnt == NULL || a == NULL)
|
|
return -1;
|
|
|
|
/* FIX ME: This is not very elegant! We use an array that we
|
|
* grow as new uint32_t are added to an array. But rather
|
|
* than be smart about it, for now we realloc() the array each
|
|
* time a new uint32_t is added! */
|
|
if (*a != NULL)
|
|
*a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
|
|
else { /* empty list */
|
|
|
|
*cnt = 0;
|
|
*a = (uint32_t *) malloc(sizeof(uint32_t));
|
|
}
|
|
if (*a == NULL) {
|
|
return -1;
|
|
}
|
|
(*a)[*cnt] = i;
|
|
(*cnt)++;
|
|
return 0;
|
|
}
|
|
|
|
static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
|
|
{
|
|
struct val_to_name *v = data;
|
|
perm_datum_t *perdatum;
|
|
|
|
perdatum = (perm_datum_t *) datum;
|
|
|
|
if (v->val == perdatum->s.value) {
|
|
v->name = key;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
|
sepol_access_vector_t av)
|
|
{
|
|
struct val_to_name v;
|
|
static char avbuf[1024];
|
|
class_datum_t *cladatum;
|
|
char *perm = NULL, *p;
|
|
unsigned int i;
|
|
int rc;
|
|
int avlen = 0, len;
|
|
|
|
cladatum = policydbp->class_val_to_struct[tclass - 1];
|
|
p = avbuf;
|
|
for (i = 0; i < cladatum->permissions.nprim; i++) {
|
|
if (av & (1 << i)) {
|
|
v.val = i + 1;
|
|
rc = hashtab_map(cladatum->permissions.table,
|
|
perm_name, &v);
|
|
if (!rc && cladatum->comdatum) {
|
|
rc = hashtab_map(cladatum->comdatum->
|
|
permissions.table, perm_name,
|
|
&v);
|
|
}
|
|
if (rc)
|
|
perm = v.name;
|
|
if (perm) {
|
|
len =
|
|
snprintf(p, sizeof(avbuf) - avlen, " %s",
|
|
perm);
|
|
if (len < 0
|
|
|| (size_t) len >= (sizeof(avbuf) - avlen))
|
|
return NULL;
|
|
p += len;
|
|
avlen += len;
|
|
}
|
|
}
|
|
}
|
|
|
|
return avbuf;
|
|
}
|
|
|
|
#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
|
|
|
|
char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
|
|
{
|
|
uint16_t value;
|
|
uint16_t low_bit;
|
|
uint16_t low_value;
|
|
unsigned int bit;
|
|
unsigned int in_range = 0;
|
|
static char xpermsbuf[2048];
|
|
xpermsbuf[0] = '\0';
|
|
char *p;
|
|
int len, xpermslen = 0;
|
|
p = xpermsbuf;
|
|
|
|
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
|
|
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
|
|
return NULL;
|
|
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
|
|
p += len;
|
|
xpermslen += len;
|
|
|
|
for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
|
|
if (!xperm_test(bit, xperms->perms))
|
|
continue;
|
|
|
|
if (in_range && next_bit_in_range(bit, xperms->perms)) {
|
|
/* continue until high value found */
|
|
continue;
|
|
} else if (next_bit_in_range(bit, xperms->perms)) {
|
|
/* low value */
|
|
low_bit = bit;
|
|
in_range = 1;
|
|
continue;
|
|
}
|
|
|
|
if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
value = xperms->driver<<8 | bit;
|
|
low_value = xperms->driver<<8 | low_bit;
|
|
if (in_range) {
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
|
|
} else {
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
|
|
}
|
|
} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
|
|
value = bit << 8;
|
|
low_value = low_bit << 8;
|
|
if (in_range) {
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
|
|
} else {
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
|
|
}
|
|
|
|
}
|
|
|
|
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
|
|
return NULL;
|
|
|
|
p += len;
|
|
xpermslen += len;
|
|
if (in_range)
|
|
in_range = 0;
|
|
}
|
|
|
|
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
|
|
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
|
|
return NULL;
|
|
|
|
return xpermsbuf;
|
|
}
|
|
|
|
/*
|
|
* The tokenize and tokenize_str functions may be used to
|
|
* replace sscanf to read tokens from buffers.
|
|
*/
|
|
|
|
/* Read a token from a buffer */
|
|
static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
|
|
{
|
|
char *tmp_buf = *ptr;
|
|
*str = NULL;
|
|
|
|
while (**ptr != '\0') {
|
|
if (isspace(delim) && isspace(**ptr)) {
|
|
(*ptr)++;
|
|
break;
|
|
} else if (!isspace(delim) && **ptr == delim) {
|
|
(*ptr)++;
|
|
break;
|
|
}
|
|
|
|
(*ptr)++;
|
|
}
|
|
|
|
*len = *ptr - tmp_buf;
|
|
/* If the end of the string has not been reached, this will ensure the
|
|
* delimiter is not included when returning the token.
|
|
*/
|
|
if (**ptr != '\0') {
|
|
(*len)--;
|
|
}
|
|
|
|
*str = strndup(tmp_buf, *len);
|
|
if (!*str) {
|
|
return -1;
|
|
}
|
|
|
|
/* Squash spaces if the delimiter is a whitespace character */
|
|
while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
|
|
(*ptr)++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* line_buf - Buffer containing string to tokenize.
|
|
* delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
|
|
* be tokenized using isspace().
|
|
* num_args - The number of parameter entries to process.
|
|
* ... - A 'char **' for each parameter.
|
|
* returns - The number of items processed.
|
|
*
|
|
* This function calls tokenize_str() to do the actual string processing. The
|
|
* caller is responsible for calling free() on each additional argument. The
|
|
* function will not tokenize more than num_args and the last argument will
|
|
* contain the remaining content of line_buf. If the delimiter is any whitespace
|
|
* character, then all whitespace will be squashed.
|
|
*/
|
|
int hidden tokenize(char *line_buf, char delim, int num_args, ...)
|
|
{
|
|
char **arg, *buf_p;
|
|
int rc, items;
|
|
size_t arg_len = 0;
|
|
va_list ap;
|
|
|
|
buf_p = line_buf;
|
|
|
|
/* Process the arguments */
|
|
va_start(ap, num_args);
|
|
|
|
for (items = 0; items < num_args && *buf_p != '\0'; items++) {
|
|
arg = va_arg(ap, char **);
|
|
|
|
/* Save the remainder of the string in arg */
|
|
if (items == num_args - 1) {
|
|
*arg = strdup(buf_p);
|
|
if (*arg == NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
rc = tokenize_str(delim, arg, &buf_p, &arg_len);
|
|
if (rc < 0) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
va_end(ap);
|
|
return items;
|
|
}
|