Merge remote-tracking branch 'aosp/upstream-master' into mymerge

Followed the following steps:

  # In repo client
  cd external/selinux
  repo sync .
  repo start mymerge .
  git merge aosp/upstream-master --no-ff # resolve any conflicts
  repo upload .

Test: compiles/boots no problems.
Change-Id: I4cd9f73fbbb818ef7fa07ff8dd183f8a7e892345
This commit is contained in:
Nick Kralevich 2018-08-06 13:55:59 -07:00
commit 4d25411b3a
79 changed files with 969 additions and 222 deletions

View file

@ -11,29 +11,30 @@ compiler:
env:
matrix:
# Test the last version of Python and Ruby together, with some linkers
- PYVER=python3.6 RUBYLIBVER=2.4
- PYVER=python3.6 RUBYLIBVER=2.4 TEST_FLAGS_OVERRIDE=1
- PYVER=python3.6 RUBYLIBVER=2.4 LINKER=gold
- PYVER=python3.6 RUBYLIBVER=2.4 LINKER=bfd
- PYVER=python3.6 RUBYLIBVER=2.5.1
- PYVER=python3.6 RUBYLIBVER=2.5.1 TEST_FLAGS_OVERRIDE=1
- PYVER=python3.6 RUBYLIBVER=2.5.1 LINKER=gold
- PYVER=python3.6 RUBYLIBVER=2.5.1 LINKER=bfd
# Test several Python versions
- PYVER=python2.7 RUBYLIBVER=2.4
- PYVER=python3.3 RUBYLIBVER=2.4
- PYVER=python3.4 RUBYLIBVER=2.4
- PYVER=python3.5 RUBYLIBVER=2.4
- PYVER=pypy RUBYLIBVER=2.4
- PYVER=pypy3 RUBYLIBVER=2.4
- PYVER=python2.7 RUBYLIBVER=2.5.1
- PYVER=python3.3 RUBYLIBVER=2.5.1
- PYVER=python3.4 RUBYLIBVER=2.5.1
- PYVER=python3.5 RUBYLIBVER=2.5.1
- PYVER=pypy RUBYLIBVER=2.5.1
- PYVER=pypy3 RUBYLIBVER=2.5.1
# Test several Ruby versions
- PYVER=python3.6 RUBYLIBVER=2.2
- PYVER=python3.6 RUBYLIBVER=2.4
- PYVER=python3.6 RUBYLIBVER=2.3
- PYVER=python3.6 RUBYLIBVER=2.2
matrix:
exclude:
- compiler: clang
env: PYVER=python3.6 RUBYLIBVER=2.4 LINKER=gold
env: PYVER=python3.6 RUBYLIBVER=2.5.1 LINKER=gold
- compiler: clang
env: PYVER=python3.6 RUBYLIBVER=2.4 LINKER=bfd
env: PYVER=python3.6 RUBYLIBVER=2.5.1 LINKER=bfd
# Use Travis-CI Ubuntu 14.04 Trusty infrastructure, "full image" variant
sudo: required
@ -64,10 +65,10 @@ addons:
install:
# Download refpolicy Makefile for sepolgen tests
- sudo mkdir -p /usr/share/selinux/default
- sudo curl --retry 10 -o /usr/share/selinux/default/Makefile 'https://raw.githubusercontent.com/TresysTechnology/refpolicy/RELEASE_2_20170204/support/Makefile.devel'
- sudo curl --retry 10 -o /usr/share/selinux/default/Makefile 'https://raw.githubusercontent.com/SELinuxProject/refpolicy/RELEASE_2_20180114/support/Makefile.devel'
- sudo sed "s,^PREFIX :=.*,PREFIX := $TRAVIS_BUILD_DIR/installdir/usr," -i /usr/share/selinux/default/Makefile
- sudo mkdir -p /usr/share/selinux/refpolicy/include
- sudo curl --retry 10 -o /usr/share/selinux/refpolicy/include/build.conf 'https://raw.githubusercontent.com/TresysTechnology/refpolicy/RELEASE_2_20170204/build.conf'
- sudo curl --retry 10 -o /usr/share/selinux/refpolicy/include/build.conf 'https://raw.githubusercontent.com/SELinuxProject/refpolicy/RELEASE_2_20180114/build.conf'
- sudo mkdir -p /etc/selinux
- echo 'SELINUXTYPE=refpolicy' | sudo tee /etc/selinux/config
@ -98,6 +99,7 @@ before_script:
- if echo "$PYVER" | grep -q pypy ; then export PYINC=-I$($PYTHON -c 'import sys;print(sys.prefix)')/include PYLIBS= ; fi
# Find the Ruby executable with version $RUBYLIBVER
- rvm reinstall ruby-$RUBYLIBVER --binary
- export RUBY="$(ls -d -1 "$HOME/.rvm/rubies/ruby-$RUBYLIBVER"*/bin/ruby | head -n 1)"
# Set the linker in $CC so that it gets used everywhere

View file

@ -1 +1 @@
2.7
2.8

View file

@ -802,6 +802,7 @@ int require_class(int pass)
if ((datum = calloc(1, sizeof(*datum))) == NULL ||
symtab_init(&datum->permissions, PERM_SYMTAB_SIZE)) {
yyerror("Out of memory!");
class_datum_destroy(datum);
return -1;
}
ret =

View file

@ -1 +1 @@
2.7
2.8

View file

@ -1 +1 @@
2.7
2.8

View file

@ -145,7 +145,7 @@ def html_to_text(html, maxcol=80):
def html_document(*body_components):
'''Wrap the body components in a HTML document structure with a valid header.
Accepts a variable number of arguments of of which canb be:
Accepts a variable number of arguments of which can be:
* string
* a sequences of strings (tuple or list).
* a callable object taking no parameters and returning a string or sequence of strings.

View file

@ -1 +1 @@
2.7
2.8

View file

@ -36,8 +36,8 @@ extern int selinux_restorecon(const char *pathname,
*/
#define SELINUX_RESTORECON_NOCHANGE 0x0002
/*
* If set set change file label to that in spec file.
* If not only change type component to that in spec file.
* If set, change file label to that in spec file.
* If not, only change type component to that in spec file.
*/
#define SELINUX_RESTORECON_SET_SPECFILE_CTX 0x0004
/*

View file

@ -1,6 +1,6 @@
.TH "selinux_boolean_sub" "3" "11 June 2012" "dwalsh@redhat.com" "SELinux API documentation"
.SH "NAME"
selinux_boolean_sub \-
selinux_boolean_sub \- Search the translated name for a boolean_name record
.
.SH "SYNOPSIS"
.B #include <selinux/selinux.h>
@ -12,7 +12,7 @@ selinux_boolean_sub \-
searches the
.I \%/etc/selinux/{POLICYTYPE}/booleans.subs_dist
file
for a maching boolean_name record. If the record exists the boolean substitution name is returned. If not
for a matching boolean_name record. If the record exists the boolean substitution name is returned. If not
.BR \%selinux_boolean_sub ()
returns the original
.IR \%boolean_name .

View file

@ -18,7 +18,7 @@ reads the contents of the
file to determine which policy files should be used for this machine.
.
.BR selinux_set_policy_root ()
sets up all all policy paths based on the alternate root
sets up all policy paths based on the alternate root
.I /etc/selinux/config
file to determine which policy files should be used for this machine.

View file

@ -119,7 +119,7 @@ By default
.BR selinux_restorecon_xattr (3)
will use the default set of specfiles described in
.BR files_contexts (5)
to calculate the initial SHA1 digest to be used for comparision.
to calculate the initial SHA1 digest to be used for comparison.
To change this default behavior
.BR selabel_open (3)
must be called specifying the required

View file

@ -92,7 +92,7 @@ The optional local and distribution substitution files that perform any path ali
.RE
.sp
The default file context series of files are:
.RS
.RS 6
.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts
.br
.I /etc/selinux/{SELINUXTYPE}/contexts/files/file_contexts.local

View file

@ -5,7 +5,7 @@ virtual_domain_context \- The SELinux virtual machine domain context configurati
.SH "DESCRIPTION"
The
.I virtual_domain_context
file contains a list of domain contexts that are available for use by the SELinux-aware virtulization API libvirt (see \fBlibvirtd\fR(8)).
file contains a list of domain contexts that are available for use by the SELinux-aware virtualization API libvirt (see \fBlibvirtd\fR(8)).
.sp
.BR selinux_virtual_domain_context_path "(3) "
will return the active policy path to this file. The default virtual domain context file is:

View file

@ -5,7 +5,7 @@ virtual_image_context \- The SELinux virtual machine image context configuration
.SH "DESCRIPTION"
The
.I virtual_image_context
file contains a list of image contexts for use by the SELinux-aware virtulization API libvirt (see \fBlibvirtd\fR(8)).
file contains a list of image contexts for use by the SELinux-aware virtualization API libvirt (see \fBlibvirtd\fR(8)).
.sp
.BR selinux_virtual_image_context_path "(3) "
will return the active policy path to this file. The default virtual image context file is:

View file

@ -98,6 +98,8 @@ LD_SONAME_FLAGS=-install_name,$(LIBSO)
endif
PCRE_LDLIBS ?= -lpcre
# override with -lfts when building on Musl libc to use fts-standalone
FTS_LDLIBS ?=
override CFLAGS += -I../include -D_GNU_SOURCE $(DISABLE_FLAGS) $(PCRE_CFLAGS)
@ -149,7 +151,7 @@ $(LIBA): $(OBJS)
$(RANLIB) $@
$(LIBSO): $(LOBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ $(PCRE_LDLIBS) -ldl -Wl,$(LD_SONAME_FLAGS)
$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ $(PCRE_LDLIBS) $(FTS_LDLIBS) -ldl -Wl,$(LD_SONAME_FLAGS)
ln -sf $@ $(TARGET)
$(LIBPC): $(LIBPC).in ../VERSION

View file

@ -193,7 +193,7 @@ static int __policy_init(const char *init_path)
{
FILE *fp;
char path[PATH_MAX];
char errormsg[PATH_MAX];
char errormsg[PATH_MAX+1024+20];
struct sepol_policy_file *pf = NULL;
int rc;
unsigned int cnt;

View file

@ -416,7 +416,7 @@ static int save_booleans(size_t boolcnt, SELboolean * boollist)
ssize_t ret;
size_t size = 0;
int val;
char boolname[BUFSIZ];
char boolname[BUFSIZ-3];
char *buffer;
inbuf = NULL;
__fsetlocking(boolf, FSETLOCKING_BYCALLER);
@ -450,6 +450,7 @@ static int save_booleans(size_t boolcnt, SELboolean * boollist)
}
}
if (i == boolcnt) {
val = !!val;
snprintf(outbuf, sizeof(outbuf),
"%s=%d\n", boolname, val);
len = strlen(outbuf);
@ -505,6 +506,7 @@ int security_set_boolean_list(size_t boolcnt, SELboolean * boollist,
size_t i;
for (i = 0; i < boolcnt; i++) {
boollist[i].value = !!boollist[i].value;
if (security_set_boolean(boollist[i].name, boollist[i].value)) {
rollback(boollist, i);
return -1;

View file

@ -153,7 +153,7 @@ static int selabel_fini(struct selabel_handle *rec,
if (rec->spec_files)
path = rec->spec_files[0];
if (compat_validate(rec, lr, path, 0))
if (compat_validate(rec, lr, path, lr->lineno))
return -1;
if (translating && !lr->ctx_trans &&

View file

@ -278,12 +278,14 @@ static inline int store_stem(struct saved_data *data, char *buf, int stem_len)
if (data->alloc_stems == num) {
struct stem *tmp_arr;
data->alloc_stems = data->alloc_stems * 2 + 16;
int alloc_stems = data->alloc_stems * 2 + 16;
tmp_arr = realloc(data->stem_arr,
sizeof(*tmp_arr) * data->alloc_stems);
if (!tmp_arr)
sizeof(*tmp_arr) * alloc_stems);
if (!tmp_arr) {
free(buf);
return -1;
}
data->alloc_stems = alloc_stems;
data->stem_arr = tmp_arr;
}
data->stem_arr[num].len = stem_len;
@ -472,6 +474,7 @@ static inline int process_line(struct selabel_handle *rec,
spec_arr[nspec].mode = 0;
spec_arr[nspec].lr.ctx_raw = context;
spec_arr[nspec].lr.lineno = lineno;
/*
* bump data->nspecs to cause closef() to cover it in its free

View file

@ -73,6 +73,7 @@ struct selabel_lookup_rec {
char * ctx_raw;
char * ctx_trans;
int validated;
unsigned lineno;
};
struct selabel_handle {

View file

@ -116,7 +116,7 @@ static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
*
* check_excluded() - Check if directory/fs is to be excluded when relabeling.
*
* file_system_count() - Calculates the the number of files to be processed.
* file_system_count() - Calculates the number of files to be processed.
* The count is only used if SELINUX_RESTORECON_PROGRESS
* is set and a mass relabel is requested.
*

View file

@ -110,7 +110,8 @@ int main(int argc, char **argv)
cumulative = 1;
break;
case 'f':
strncpy(avcstatfile, optarg, sizeof avcstatfile);
strncpy(avcstatfile, optarg, sizeof(avcstatfile) - 1);
avcstatfile[sizeof(avcstatfile)-1] = '\0';
break;
case 'h':
case '-':

View file

@ -19,7 +19,7 @@ static __attribute__ ((__noreturn__)) void usage(const char *name, const char *d
int main(int argc, char **argv)
{
char **list, *usercon = NULL, *cur_context = NULL;
char **list, *cur_context = NULL;
char *user = NULL, *level = NULL;
int ret, i, opt;
@ -40,6 +40,7 @@ int main(int argc, char **argv)
if (!is_selinux_enabled()) {
fprintf(stderr,
"getconlist may be used only on a SELinux kernel.\n");
free(level);
return 1;
}
@ -49,6 +50,7 @@ int main(int argc, char **argv)
if (((argc - optind) < 2)) {
if (getcon(&cur_context) < 0) {
fprintf(stderr, "Couldn't get current context.\n");
free(level);
return 2;
}
} else
@ -67,7 +69,7 @@ int main(int argc, char **argv)
freeconary(list);
}
free(usercon);
free(level);
return 0;
}

View file

@ -1 +1 @@
2.7
2.8

View file

@ -23,7 +23,7 @@ The count function will return the number of all objects in the selected locatio
.B Parameters:
The
.I handle
is used to track persistent state across semanage calls, and for error reporting. The number of objects will be stored at the location poined by
is used to track persistent state across semanage calls, and for error reporting. The number of objects will be stored at the location pointed by
.I response.
.TP

View file

@ -25,7 +25,7 @@ The list function will return an array of all the objects in the selected locati
.B Parameters:
The
.I handle
is used to track persistent state across semanage calls, and for error reporting. The function will allocate and populate the the array of objects, and store it at the location pointed by
is used to track persistent state across semanage calls, and for error reporting. The function will allocate and populate the array of objects, and store it at the location pointed by
.I objects.
It will write the number of objects at the location pointed by
.I count.

View file

@ -1481,7 +1481,7 @@ rebuild:
retval = semanage_copy_file(path,
semanage_path(SEMANAGE_TMP,
SEMANAGE_STORE_SEUSERS),
sh->conf->file_mode);
0);
if (retval < 0)
goto cleanup;
pseusers->dtable->drop_cache(pseusers->dbase);
@ -1499,7 +1499,7 @@ rebuild:
retval = semanage_copy_file(path,
semanage_path(SEMANAGE_TMP,
SEMANAGE_USERS_EXTRA),
sh->conf->file_mode);
0);
if (retval < 0)
goto cleanup;
pusers_extra->dtable->drop_cache(pusers_extra->dbase);

View file

@ -972,9 +972,13 @@ static int add_user(genhomedircon_settings_t * s,
char uid[11];
char gid[11];
errno = 0;
/* Allocate space for the getpwnam_r buffer */
rbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
if (rbuflen <= 0)
if (rbuflen == -1 && errno == 0)
/* sysconf returning -1 with no errno means indeterminate size */
rbuflen = 1024;
else if (rbuflen <= 0)
goto cleanup;
rbuf = malloc(rbuflen);
if (rbuf == NULL)
@ -1057,8 +1061,12 @@ static int get_group_users(genhomedircon_settings_t * s,
struct group grstorage, *group = NULL;
struct passwd *pw = NULL;
errno = 0;
grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
if (grbuflen <= 0)
if (grbuflen == -1 && errno == 0)
/* sysconf returning -1 with no errno means indeterminate size */
grbuflen = 1024;
else if (grbuflen <= 0)
goto cleanup;
grbuf = malloc(grbuflen);
if (grbuf == NULL)

View file

@ -1350,6 +1350,8 @@ static char **split_args(const char *arg0, char *arg_string,
if (isspace(*s) && !in_quote && !in_dquote) {
if (arg != NULL) {
rc = append_arg(&argv, &num_args, arg);
if (rc)
goto cleanup;
free(arg);
arg = NULL;
}
@ -1366,6 +1368,8 @@ static char **split_args(const char *arg0, char *arg_string,
}
if (arg != NULL) {
rc = append_arg(&argv, &num_args, arg);
if (rc)
goto cleanup;
free(arg);
arg = NULL;
}
@ -1593,7 +1597,12 @@ static int semanage_install_final_tmp(semanage_handle_t * sh)
/* skip genhomedircon if configured */
if (sh->conf->disable_genhomedircon &&
i == SEMANAGE_FC_HOMEDIRS) continue;
if (strlen(dst) >= sizeof(fn)) {
ERR(sh, "Unable to compose the final paths.");
status = -1;
goto cleanup;
}
strcpy(fn, dst);
ret = semanage_mkpath(sh, dirname(fn));
if (ret < 0) {

View file

@ -1 +1 @@
2.7
2.8

View file

@ -2923,7 +2923,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
rc = cil_fill_ipaddr(pc->cl_head, ipaddr);
if (rc != SEPOL_OK) {
cil_log(CIL_ERR, "Failed to create anonymous ip address, rc; %d\n", rc);
cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc);
cil_destroy_ipaddr(ipaddr);
goto exit;
}

View file

@ -339,7 +339,7 @@ static int cil_expr_to_string(struct cil_list *expr, char **out)
int pos = 0;
cil_list_for_each(curr, expr) {
if (pos > COND_EXPR_MAXDEPTH) {
if (pos >= COND_EXPR_MAXDEPTH) {
rc = SEPOL_ERR;
goto exit;
}
@ -512,7 +512,7 @@ void cil_tree_print_expr(struct cil_list *datum_expr, struct cil_list *str_expr)
} else {
rc = cil_expr_to_string(str_expr, &expr_str);
}
if (rc < 0) {
if (rc != SEPOL_OK) {
cil_log(CIL_INFO, "ERROR)");
return;
}

View file

@ -646,9 +646,6 @@ extern int policydb_context_isvalid(const policydb_t * p,
extern void symtabs_destroy(symtab_t * symtab);
extern int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p);
typedef void (*hashtab_destroy_func_t) (hashtab_key_t k, hashtab_datum_t d,
void *args);
extern hashtab_destroy_func_t get_symtab_destroy_func(int sym_num);
extern void class_perm_node_init(class_perm_node_t * x);
extern void type_set_init(type_set_t * x);

View file

@ -201,11 +201,11 @@ static int load_users(struct policydb *policydb, const char *path)
if (!(*p))
BADLINE();
q = p;
while (*p && strncasecmp(p, "range", 5))
while (*p && (!isspace(*p) || strncasecmp(p + 1, "range", 5)))
p++;
if (!(*p))
if (!(*p) || p == q)
BADLINE();
*--p = 0;
*p = 0;
p++;
scontext = malloc(p - q);

View file

@ -80,10 +80,13 @@ static char *create_str_helper(const char *fmt, int num, va_list vargs)
goto exit;
}
va_end(vargs2);
return str;
exit:
free(str);
va_end(vargs2);
return NULL;
}

View file

@ -298,6 +298,8 @@ static int roles_gather_map(char *key, void *data, void *args)
role_node->role = role;
rc = list_prepend((struct list *)args, role_node);
if (rc != 0)
free(role_node);
return rc;
}
@ -344,6 +346,11 @@ static int typealiases_gather_map(char *key, void *data, void *arg)
goto exit;
}
}
/* As typealias_lists[scope_id] does not hold the
* ownership of its items (typealias_list_destroy does
* not free the list items), "key" does not need to be
* strdup'ed before it is inserted in the list.
*/
list_prepend(typealias_lists[scope_id], key);
}
}
@ -1002,6 +1009,12 @@ static int ebitmap_to_names(struct ebitmap *map, char **vals_to_names, char ***n
}
}
if (!num) {
*names = NULL;
*num_names = 0;
goto exit;
}
name_arr = malloc(sizeof(*name_arr) * num);
if (name_arr == NULL) {
log_err("Out of memory");
@ -1092,7 +1105,6 @@ static int roletype_role_in_ancestor_to_cil(struct policydb *pdb, struct stack *
goto exit;
}
curr = role_list->head;
for (curr = role_list->head; curr != NULL; curr = curr->next) {
role_node = curr->data;
if (!is_id_in_ancestor_scope(pdb, decl_stack, role_node->role_name, SYM_ROLES)) {
@ -1284,7 +1296,6 @@ static int cond_expr_to_cil(int indent, struct policydb *pdb, struct cond_expr *
rc = -1;
goto exit;
}
num_params = 0;
} else {
switch(curr->expr_type) {
case COND_NOT: op = "not"; break;
@ -1824,8 +1835,6 @@ static int constraint_expr_to_string(struct policydb *pdb, struct constraint_exp
free(names);
names = NULL;
}
num_params = 0;
} else {
switch (expr->expr_type) {
case CEXPR_NOT: op = "not"; break;
@ -1917,10 +1926,12 @@ exit:
free(new_val);
free(val1);
free(val2);
while ((val1 = stack_pop(stack)) != NULL) {
free(val1);
if (stack != NULL) {
while ((val1 = stack_pop(stack)) != NULL) {
free(val1);
}
stack_destroy(&stack);
}
stack_destroy(&stack);
return rc;
}
@ -4221,7 +4232,6 @@ exit:
int sepol_ppfile_to_module_package(FILE *fp, struct sepol_module_package **mod_pkg)
{
int rc = -1;
FILE *f = NULL;
struct sepol_policy_file *pf = NULL;
struct sepol_module_package *pkg = NULL;
char *data = NULL;
@ -4273,9 +4283,6 @@ exit:
free(data);
sepol_policy_file_free(pf);
if (f != NULL) {
fclose(f);
}
if (rc != 0) {
sepol_module_package_free(pkg);

View file

@ -83,7 +83,7 @@ static int node_parse_addr(sepol_handle_t * handle,
}
/* Allocates a sufficiently large buffer (addr, addr_sz)
* according the the protocol */
* according to the protocol */
static int node_alloc_addr(sepol_handle_t * handle,
int proto, char **addr, size_t * addr_sz)

View file

@ -1573,14 +1573,6 @@ int scope_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
return 0;
}
hashtab_destroy_func_t get_symtab_destroy_func(int sym_num)
{
if (sym_num < 0 || sym_num >= SYM_NUM) {
return NULL;
}
return (hashtab_destroy_func_t) destroy_f[sym_num];
}
/*
* Load the initial SIDs specified in a policy database
* structure into a SID table.

View file

@ -210,7 +210,6 @@ int read_binary_policy(const char *path, policydb_t *p)
if ((in_fp = fopen(path, "rb")) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", path,
strerror(errno));
sepol_handle_destroy(f.handle);
return -1;
}
@ -220,7 +219,6 @@ int read_binary_policy(const char *path, policydb_t *p)
f.fp = in_fp;
rc = policydb_read(p, &f, 0);
sepol_handle_destroy(f.handle);
fclose(in_fp);
return rc;
}
@ -256,7 +254,7 @@ int write_binary_policy(const char *path, policydb_t *p)
if ((out_fp = fopen(path, "w" )) == NULL) {
fprintf(stderr, "Unable to open %s: %s\n", path,
strerror(errno));
sepol_handle_destroy(f.handle);
sepol_handle_destroy(handle);
return -1;
}

View file

@ -1 +1 @@
2.7
2.8

View file

@ -59,7 +59,7 @@ defines a translation of s15:c0.c1023 to SystemHigh. c0.c1023 is shorthand for a
.TP
s0\-s15:c0.c1023=SystemLow\-SystemHigh\fR
defines a range translation of of s0\-s15:c0.c1023 to SystemLow\-SystemHigh. The two range components are separated by a dash.
defines a range translation of s0\-s15:c0.c1023 to SystemLow\-SystemHigh. The two range components are separated by a dash.
.TP
s0:c0=PatientRecord\fR

View file

@ -708,6 +708,7 @@ append(affix_t **affixes, const char *val) {
err:
log_error("allocation error %s", strerror(errno));
free(affix);
return -1;
}
@ -1517,8 +1518,10 @@ trans_context(const security_context_t incon, security_context_t *rcon) {
} else {
trans = compute_trans_from_raw(range, domain);
if (trans)
if (add_cache(domain, range, trans) < 0)
if (add_cache(domain, range, trans) < 0) {
free(range);
return -1;
}
}
if (lrange && urange) {
@ -1526,12 +1529,15 @@ trans_context(const security_context_t incon, security_context_t *rcon) {
if (! ltrans) {
ltrans = compute_trans_from_raw(lrange, domain);
if (ltrans) {
if (add_cache(domain, lrange, ltrans) < 0)
if (add_cache(domain, lrange, ltrans) < 0) {
free(range);
return -1;
}
} else {
ltrans = strdup(lrange);
if (! ltrans) {
log_error("strdup failed %s", strerror(errno));
free(range);
return -1;
}
}
@ -1541,25 +1547,36 @@ trans_context(const security_context_t incon, security_context_t *rcon) {
if (! utrans) {
utrans = compute_trans_from_raw(urange, domain);
if (utrans) {
if (add_cache(domain, urange, utrans) < 0)
if (add_cache(domain, urange, utrans) < 0) {
free(ltrans);
free(range);
return -1;
}
} else {
utrans = strdup(urange);
if (! utrans) {
log_error("strdup failed %s", strerror(errno));
return -1;
}
}
free(ltrans);
free(range);
return -1;
}
}
}
if (strcmp(ltrans, utrans) == 0) {
if (asprintf(&trans, "%s", ltrans) < 0) {
log_error("asprintf failed %s", strerror(errno));
free(utrans);
free(ltrans);
free(range);
return -1;
}
} else {
if (asprintf(&trans, "%s-%s", ltrans, utrans) < 0) {
log_error("asprintf failed %s", strerror(errno));
free(utrans);
free(ltrans);
free(range);
return -1;
}
}
@ -1629,13 +1646,17 @@ untrans_context(const security_context_t incon, security_context_t *rcon) {
if (!canonical) {
canonical = compute_trans_from_raw(raw, domain);
if (canonical && strcmp(canonical, range))
if (add_cache(domain, raw, canonical) < 0)
if (add_cache(domain, raw, canonical) < 0) {
free(range);
return -1;
}
}
if (canonical)
free(canonical);
if (add_cache(domain, raw, range) < 0)
if (add_cache(domain, raw, range) < 0) {
free(range);
return -1;
}
} else {
log_debug("untrans_context unable to compute raw context %s\n", range);
}
@ -1650,17 +1671,24 @@ untrans_context(const security_context_t incon, security_context_t *rcon) {
if (!canonical) {
canonical = compute_trans_from_raw(lraw, domain);
if (canonical)
if (add_cache(domain, lraw, canonical) < 0)
if (add_cache(domain, lraw, canonical) < 0) {
free(lraw);
free(range);
return -1;
}
}
if (canonical)
free(canonical);
if (add_cache(domain, lraw, lrange) < 0)
if (add_cache(domain, lraw, lrange) < 0) {
free(lraw);
free(range);
return -1;
}
} else {
lraw = strdup(lrange);
if (! lraw) {
log_error("strdup failed %s", strerror(errno));
free(range);
return -1;
}
}
@ -1674,17 +1702,27 @@ untrans_context(const security_context_t incon, security_context_t *rcon) {
if (!canonical) {
canonical = compute_trans_from_raw(uraw, domain);
if (canonical)
if (add_cache(domain, uraw, canonical) < 0)
if (add_cache(domain, uraw, canonical) < 0) {
free(uraw);
free(lraw);
free(range);
return -1;
}
}
if (canonical)
free(canonical);
if (add_cache(domain, uraw, urange) < 0)
if (add_cache(domain, uraw, urange) < 0) {
free(uraw);
free(lraw);
free(range);
return -1;
}
} else {
uraw = strdup(urange);
if (! uraw) {
log_error("strdup failed %s", strerror(errno));
free(lraw);
free(range);
return -1;
}
}
@ -1694,11 +1732,17 @@ untrans_context(const security_context_t incon, security_context_t *rcon) {
if (strcmp(lraw, uraw) == 0) {
if (asprintf(&raw, "%s", lraw) < 0) {
log_error("asprintf failed %s", strerror(errno));
free(uraw);
free(lraw);
free(range);
return -1;
}
} else {
if (asprintf(&raw, "%s-%s", lraw, uraw) < 0) {
log_error("asprintf failed %s", strerror(errno));
free(uraw);
free(lraw);
free(range);
return -1;
}
}

View file

@ -1 +1 @@
2.7
2.8

View file

@ -73,7 +73,6 @@ int main(int argc, char **argv)
const char *ofile = NULL;
FILE *in = NULL;
FILE *out = NULL;
int outfd = -1;
// ignore sigpipe so we can check the return code of write, and potentially
// return a more helpful error message
@ -159,12 +158,6 @@ exit:
if (out != NULL) {
fclose(out);
}
if (outfd != -1) {
close(outfd);
if (rc != 0) {
unlink(argv[2]);
}
}
sepol_module_package_free(mod_pkg);
return rc;

View file

@ -44,7 +44,7 @@ specified by that range. If the
or
.B --preserve-environment
option is specified, the shell with the new SELinux context will preserve environment variables,
otherwise a new minimal enviroment is created.
otherwise a new minimal environment is created.
.PP
Additional arguments
.I ARGS

View file

@ -309,7 +309,7 @@ case "$1" in
usage
exit 1
fi
> /.autorelabel
> /.autorelabel || exit $?
[ -z "$FORCEFLAG" ] || echo -n "$FORCEFLAG " >> /.autorelabel
[ -z "$BOOTTIME" ] || echo -N $BOOTTIME >> /.autorelabel
# Force full relabel if / does not have a label on it

View file

@ -309,7 +309,7 @@ static void cmd_line(int argc, char *argv[])
}
}
if (!done) { /* defualt, if nothing specified */
if (!done) { /* default, if nothing specified */
opts->disp_user = TRUE;
opts->disp_role = TRUE;
opts->disp_type = TRUE;
@ -646,6 +646,7 @@ static void disp_con(security_context_t scon_raw)
disp__con_val("clearance", NULL, &color);
if (opts->disp_mlsr)
disp__con_val("mls-range", NULL, &color);
freecon(scon_trans);
return;
}

View file

@ -17,6 +17,7 @@
#include <unistd.h>
#include <libgen.h>
#include <ctype.h>
#include <limits.h>
#define PROC_BASE "/proc"
#define MAX_CHECK 50
@ -61,6 +62,7 @@ int cmp_cmdline(const char *command, int pid)
int pidof(const char *command)
{
/* inspired by killall5.c from psmisc */
char stackpath[PATH_MAX + 1], *p;
DIR *dir;
struct dirent *de;
int pid, ret = -1, self = getpid();
@ -70,6 +72,11 @@ int pidof(const char *command)
return -1;
}
/* Resolve the path if it contains symbolic links */
p = realpath(command, stackpath);
if (p)
command = p;
while ((de = readdir(dir)) != NULL) {
errno = 0;
pid = (int)strtol(de->d_name, (char **)NULL, 10);
@ -430,6 +437,7 @@ int main(int argc, char **argv)
printf("%s\n", context);
freecon(context);
}
free(pc[i]);
}
printf("\nFile contexts:\n");
@ -472,6 +480,7 @@ int main(int argc, char **argv)
freecon(context);
}
}
free(fc[i]);
}
return 0;

View file

@ -6,6 +6,14 @@
#include "restore.h"
#include <glob.h>
#ifndef GLOB_BRACE
#define GLOB_BRACE 0
#endif
#ifndef GLOB_TILDE
#define GLOB_TILDE 0
#endif
char **exclude_list;
int exclude_count;

View file

@ -1 +1 @@
2.7
2.8

View file

@ -86,6 +86,8 @@ class AuditToPolicy:
dest="type")
parser.add_option("--perm-map", dest="perm_map", help="file name of perm map")
parser.add_option("--interface-info", dest="interface_info", help="file name of interface information")
parser.add_option("-x", "--xperms", action="store_true", dest="xperms",
default=False, help="generate extended permission rules")
parser.add_option("--debug", dest="debug", action="store_true", default=False,
help="leave generated modules for -M")
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0]) == "audit2why"),
@ -314,6 +316,10 @@ class AuditToPolicy:
ifs, perm_maps = self.__load_interface_info()
g.set_gen_refpol(ifs, perm_maps)
# Extended permissions
if self.__options.xperms:
g.set_gen_xperms(True)
# Explanation
if self.__options.verbose:
g.set_gen_explain(policygen.SHORT_EXPLANATION)

View file

@ -85,6 +85,9 @@ This is the default behavior.
Generate reference policy using installed macros.
This attempts to match denials against interfaces and may be inaccurate.
.TP
.B "\-x" | "\-\-xperms"
Generate extended permission access vector rules
.TP
.B "\-w" | "\-\-why"
Translates SELinux audit messages into a description of why the access was denied

View file

@ -34,3 +34,4 @@ node=mary.example.com type=AVC msg=audit(1166023021.373:910): avc: denied { re
node=lilly.example.com type=AVC_PATH msg=audit(1164783469.561:109): path="/linuxtest/LVT/lvt/log.current"
node=lilly.example.com type=SYSCALL msg=audit(1164783469.561:109): arch=14 syscall=11 success=yes exit=0 a0=10120520 a1=10120a78 a2=10120970 a3=118 items=0 ppid=8310 pid=8311 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) comm="smbd" exe="/usr/sbin/smbd" subj=root:system_r:smbd_t:s0 key=(null)
node=lilly.example.com type=AVC msg=audit(1164783469.561:109): avc: denied { append } for pid=8311 comm="smbd" name="log.current" dev=dm-0 ino=130930 scontext=root:system_r:smbd_t:s0 tcontext=root:object_r:default_t:s0 tclass=dir
node=lilly.example.com type=AVC msg=audit(1164783469.561:109): avc: denied { ioctl } for pid=8311 comm="smbd" name="log.current" ioctlcmd=0x2a scontext=root:system_r:smbd_t:s0 tcontext=root:object_r:default_t:s0 tclass=tcp_socket

View file

@ -47,5 +47,14 @@ class Audit2allowTests(unittest.TestCase):
print(out, err)
self.assertSuccess("audit2why", p.returncode, err)
def test_xperms(self):
"Verify that xperms generation works"
p = Popen(['python', './audit2allow', "-x", "-i", "test.log"], stdout=PIPE)
out, err = p.communicate()
if err:
print(out, err)
self.assertTrue(b"allowxperm" in out)
self.assertSuccess("xperms", p.returncode, err)
if __name__ == "__main__":
unittest.main()

View file

@ -101,6 +101,8 @@ ftype_to_audit = {"": "any",
try:
import audit
#test if audit module is enabled
audit.audit_close(audit.audit_open())
class logger:
@ -138,7 +140,7 @@ try:
self.log_list = []
self.log_change_list = []
except:
except (OSError, ImportError):
class logger:
def __init__(self):
@ -593,7 +595,6 @@ class loginRecords(semanageRecords):
semanage_seuser_key_free(k)
semanage_seuser_free(u)
self.mylog.log("login", name, sename=sename, serange=serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
def add(self, name, sename, serange):
try:
@ -601,7 +602,6 @@ class loginRecords(semanageRecords):
self.__add(name, sename, serange)
self.commit()
except ValueError as error:
self.mylog.commit(0)
raise error
def __modify(self, name, sename="", serange=""):
@ -653,7 +653,6 @@ class loginRecords(semanageRecords):
semanage_seuser_key_free(k)
semanage_seuser_free(u)
self.mylog.log("login", name, sename=self.sename, serange=self.serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
def modify(self, name, sename="", serange=""):
try:
@ -661,7 +660,6 @@ class loginRecords(semanageRecords):
self.__modify(name, sename, serange)
self.commit()
except ValueError as error:
self.mylog.commit(0)
raise error
def __delete(self, name):
@ -694,8 +692,6 @@ class loginRecords(semanageRecords):
rec, self.sename, self.serange = selinux.getseuserbyname("__default__")
range, (rc, serole) = userrec.get(self.sename)
self.mylog.log_remove("login", name, sename=self.sename, serange=self.serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
def delete(self, name):
try:
self.begin()
@ -703,7 +699,6 @@ class loginRecords(semanageRecords):
self.commit()
except ValueError as error:
self.mylog.commit(0)
raise error
def deleteall(self):
@ -717,7 +712,6 @@ class loginRecords(semanageRecords):
self.__delete(semanage_seuser_get_name(u))
self.commit()
except ValueError as error:
self.mylog.commit(0)
raise error
def get_all_logins(self):
@ -2299,7 +2293,7 @@ class fcontextRecords(semanageRecords):
raise ValueError(_("Target %s is not valid. Target is not allowed to end with '/'") % target)
if substitute != "/" and substitute[-1] == "/":
raise ValueError(_("Substiture %s is not valid. Substitute is not allowed to end with '/'") % substitute)
raise ValueError(_("Substitute %s is not valid. Substitute is not allowed to end with '/'") % substitute)
if target in self.equiv.keys():
raise ValueError(_("Equivalence class for %s already exists") % target)
@ -2651,7 +2645,7 @@ class booleanRecords(semanageRecords):
self.current_booleans = []
ptype = None
if self.store is None or self.store == ptype:
if self.store == "" or self.store == ptype:
self.modify_local = True
else:
self.modify_local = False

View file

@ -78,6 +78,7 @@ class AccessVector(util.Comparison):
.obj_class - The object class to which access is allowed. [String or None]
.perms - The permissions allowed to the object class. [IdSet]
.audit_msgs - The audit messages that generated this access vector [List of strings]
.xperms - Extended permissions attached to the AV. [Dictionary {operation: xperm set}]
"""
def __init__(self, init_list=None):
if init_list:
@ -87,9 +88,11 @@ class AccessVector(util.Comparison):
self.tgt_type = None
self.obj_class = None
self.perms = refpolicy.IdSet()
self.audit_msgs = []
self.type = audit2why.TERULE
self.data = []
self.audit_msgs = []
self.type = audit2why.TERULE
self.data = []
self.xperms = {}
# when implementing __eq__ also __hash__ is needed on py2
# if object is muttable __hash__ should be None
self.__hash__ = None
@ -131,6 +134,15 @@ class AccessVector(util.Comparison):
l.extend(sorted(self.perms))
return l
def merge(self, av):
"""Add permissions and extended permissions from AV"""
self.perms.update(av.perms)
for op in av.xperms:
if op not in self.xperms:
self.xperms[op] = refpolicy.XpermSet()
self.xperms[op].extend(av.xperms[op])
def __str__(self):
return self.to_string()
@ -260,28 +272,28 @@ class AccessVectorSet:
def add(self, src_type, tgt_type, obj_class, perms, audit_msg=None, avc_type=audit2why.TERULE, data=[]):
"""Add an access vector to the set.
"""
tgt = self.src.setdefault(src_type, { })
cls = tgt.setdefault(tgt_type, { })
if (obj_class, avc_type) in cls:
access = cls[obj_class, avc_type]
else:
access = AccessVector()
access.src_type = src_type
access.tgt_type = tgt_type
access.obj_class = obj_class
access.data = data
access.type = avc_type
cls[obj_class, avc_type] = access
av = AccessVector()
av.src_type = src_type
av.tgt_type = tgt_type
av.obj_class = obj_class
av.perms = perms
av.data = data
av.type = avc_type
access.perms.update(perms)
if audit_msg:
access.audit_msgs.append(audit_msg)
self.add_av(av, audit_msg)
def add_av(self, av, audit_msg=None):
"""Add an access vector to the set."""
self.add(av.src_type, av.tgt_type, av.obj_class, av.perms)
tgt = self.src.setdefault(av.src_type, { })
cls = tgt.setdefault(av.tgt_type, { })
if (av.obj_class, av.type) in cls:
cls[av.obj_class, av.type].merge(av)
else:
cls[av.obj_class, av.type] = av
if audit_msg:
cls[av.obj_class, av.type].audit_msgs.append(audit_msg)
def avs_extract_types(avs):
types = refpolicy.IdSet()

View file

@ -152,6 +152,7 @@ class AVCMessage(AuditMessage):
access - list of accesses that were allowed or denied
denial - boolean indicating whether this was a denial (True) or granted
(False) message.
ioctlcmd - ioctl 'request' parameter
An example audit message generated from the audit daemon looks like (line breaks
added):
@ -178,6 +179,7 @@ class AVCMessage(AuditMessage):
self.name = ""
self.accesses = []
self.denial = True
self.ioctlcmd = None
self.type = audit2why.TERULE
def __parse_access(self, recs, start):
@ -237,6 +239,11 @@ class AVCMessage(AuditMessage):
self.exe = fields[1][1:-1]
elif fields[0] == "name":
self.name = fields[1][1:-1]
elif fields[0] == "ioctlcmd":
try:
self.ioctlcmd = int(fields[1], 16)
except ValueError:
pass
if not found_src or not found_tgt or not found_class or not found_access:
raise ValueError("AVC message in invalid format [%s]\n" % self.message)
@ -522,13 +529,20 @@ class AuditParser:
for avc in self.avc_msgs:
if avc.denial != True and only_denials:
continue
if avc_filter:
if avc_filter.filter(avc):
av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
avc.accesses, avc, avc_type=avc.type, data=avc.data)
else:
av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
avc.accesses, avc, avc_type=avc.type, data=avc.data)
if not avc_filter or avc_filter.filter(avc):
av = access.AccessVector([avc.scontext.type, avc.tcontext.type,
avc.tclass] + avc.accesses)
av.data = avc.data
av.type = avc.type
if avc.ioctlcmd:
xperm_set = refpolicy.XpermSet()
xperm_set.add(avc.ioctlcmd)
av.xperms["ioctl"] = xperm_set
av_set.add_av(av, audit_msg=avc)
return av_set
class AVCTypeFilter:

View file

@ -22,7 +22,7 @@ import re
# Select the correct location for the development files based on a
# path variable (optionally read from a configuration file)
class PathChoooser(object):
class PathChooser(object):
def __init__(self, pathname):
self.config = dict()
if not os.path.exists(pathname):
@ -68,10 +68,10 @@ def attribute_info():
return data_dir() + "/attribute_info"
def refpolicy_makefile():
chooser = PathChoooser("/etc/selinux/sepolgen.conf")
chooser = PathChooser("/etc/selinux/sepolgen.conf")
return chooser("Makefile")
def headers():
chooser = PathChoooser("/etc/selinux/sepolgen.conf")
chooser = PathChooser("/etc/selinux/sepolgen.conf")
return chooser("include")

View file

@ -50,10 +50,11 @@ class PolicyGenerator:
in the form of access vectors.
It generates allow rules and optionally module require
statements and reference policy interfaces. By default
only allow rules are generated. The methods .set_gen_refpol
and .set_gen_requires turns on interface generation and
requires generation respectively.
statements, reference policy interfaces, and extended
permission access vector rules. By default only allow rules
are generated. The methods .set_gen_refpol, .set_gen_requires
and .set_gen_xperms turns on interface generation,
requires generation, and xperms rules genration respectively.
PolicyGenerator can also optionally add comments explaining
why a particular access was allowed based on the audit
@ -82,6 +83,7 @@ class PolicyGenerator:
self.module = refpolicy.Module()
self.dontaudit = False
self.xperms = False
self.domains = None
def set_gen_refpol(self, if_set=None, perm_maps=None):
@ -120,6 +122,12 @@ class PolicyGenerator:
def set_gen_dontaudit(self, dontaudit):
self.dontaudit = dontaudit
def set_gen_xperms(self, xperms):
"""Set whether extended permission access vector rules
are generated.
"""
self.xperms = xperms
def __set_module_style(self):
if self.ifgen:
refpolicy = True
@ -153,51 +161,69 @@ class PolicyGenerator:
"""Return the generated module"""
return self.module
def __add_allow_rules(self, avs):
for av in avs:
rule = refpolicy.AVRule(av)
def __add_av_rule(self, av):
"""Add access vector rule.
"""
rule = refpolicy.AVRule(av)
if self.dontaudit:
rule.rule_type = rule.DONTAUDIT
rule.comment = ""
if self.explain:
rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
if av.type == audit2why.ALLOW:
rule.comment += "\n#!!!! This avc is allowed in the current policy"
if av.xperms:
rule.comment += "\n#!!!! This av rule may have been overridden by an extended permission av rule"
if av.type == audit2why.DONTAUDIT:
rule.comment += "\n#!!!! This avc has a dontaudit rule in the current policy"
if av.type == audit2why.BOOLEAN:
if len(av.data) > 1:
rule.comment += "\n#!!!! This avc can be allowed using one of the these booleans:\n# %s" % ", ".join([x[0] for x in av.data])
else:
rule.comment += "\n#!!!! This avc can be allowed using the boolean '%s'" % av.data[0][0]
if av.type == audit2why.CONSTRAINT:
rule.comment += "\n#!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access."
rule.comment += "\n#Constraint rule: "
rule.comment += "\n#\t" + av.data[0]
for reason in av.data[1:]:
rule.comment += "\n#\tPossible cause is the source %s and target %s are different." % reason
try:
if ( av.type == audit2why.TERULE and
"write" in av.perms and
( "dir" in av.obj_class or "open" in av.perms )):
if not self.domains:
self.domains = seinfo(ATTRIBUTE, name="domain")[0]["types"]
types=[]
for i in [x[TCONTEXT] for x in sesearch([ALLOW], {SCONTEXT: av.src_type, CLASS: av.obj_class, PERMS: av.perms})]:
if i not in self.domains:
types.append(i)
if len(types) == 1:
rule.comment += "\n#!!!! The source type '%s' can write to a '%s' of the following type:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
elif len(types) >= 1:
rule.comment += "\n#!!!! The source type '%s' can write to a '%s' of the following types:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
except:
pass
self.module.children.append(rule)
def __add_ext_av_rules(self, av):
"""Add extended permission access vector rules.
"""
for op in av.xperms.keys():
extrule = refpolicy.AVExtRule(av, op)
if self.dontaudit:
rule.rule_type = rule.DONTAUDIT
rule.comment = ""
if self.explain:
rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
if av.type == audit2why.ALLOW:
rule.comment += "\n#!!!! This avc is allowed in the current policy"
if av.type == audit2why.DONTAUDIT:
rule.comment += "\n#!!!! This avc has a dontaudit rule in the current policy"
if av.type == audit2why.BOOLEAN:
if len(av.data) > 1:
rule.comment += "\n#!!!! This avc can be allowed using one of the these booleans:\n# %s" % ", ".join([x[0] for x in av.data])
else:
rule.comment += "\n#!!!! This avc can be allowed using the boolean '%s'" % av.data[0][0]
if av.type == audit2why.CONSTRAINT:
rule.comment += "\n#!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access."
rule.comment += "\n#Constraint rule: "
rule.comment += "\n#\t" + av.data[0]
for reason in av.data[1:]:
rule.comment += "\n#\tPossible cause is the source %s and target %s are different." % reason
try:
if ( av.type == audit2why.TERULE and
"write" in av.perms and
( "dir" in av.obj_class or "open" in av.perms )):
if not self.domains:
self.domains = seinfo(ATTRIBUTE, name="domain")[0]["types"]
types=[]
for i in [x[TCONTEXT] for x in sesearch([ALLOW], {SCONTEXT: av.src_type, CLASS: av.obj_class, PERMS: av.perms})]:
if i not in self.domains:
types.append(i)
if len(types) == 1:
rule.comment += "\n#!!!! The source type '%s' can write to a '%s' of the following type:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
elif len(types) >= 1:
rule.comment += "\n#!!!! The source type '%s' can write to a '%s' of the following types:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
except:
pass
self.module.children.append(rule)
extrule.rule_type = extrule.DONTAUDITXPERM
self.module.children.append(extrule)
def add_access(self, av_set):
"""Add the access from the access vector set to this
@ -215,7 +241,10 @@ class PolicyGenerator:
raw_allow = av_set
# Generate the raw allow rules from the filtered list
self.__add_allow_rules(raw_allow)
for av in raw_allow:
self.__add_av_rule(av)
if self.xperms and av.xperms:
self.__add_ext_av_rules(av)
def add_role_types(self, role_type_set):
for role_type in role_type_set:

View file

@ -109,6 +109,9 @@ class Node(PolicyBase):
def avrules(self):
return filter(lambda x: isinstance(x, AVRule), walktree(self))
def avextrules(self):
return filter(lambda x: isinstance(x, AVExtRule), walktree(self))
def typerules(self):
return filter(lambda x: isinstance(x, TypeRule), walktree(self))
@ -284,6 +287,11 @@ class SecurityContext(Leaf):
Raises ValueError if the string is not parsable as a security context.
"""
# try to translate the context string to raw form
raw = selinux.selinux_trans_to_raw_context(context)
if raw[0] == 0:
context = raw[1]
fields = context.split(":")
if len(fields) < 3:
raise ValueError("context string [%s] not in a valid format" % context)
@ -347,6 +355,65 @@ class ObjectClass(Leaf):
self.name = name
self.perms = IdSet()
class XpermSet():
"""Extended permission set.
This class represents one or more extended permissions
represented by numeric values or ranges of values. The
.complement attribute is used to specify all permission
except those specified.
Two xperm set can be merged using the .extend() method.
"""
def __init__(self, complement=False):
self.complement = complement
self.ranges = []
def __normalize_ranges(self):
"""Ensure that ranges are not overlapping.
"""
self.ranges.sort()
i = 0
while i < len(self.ranges):
while i + 1 < len(self.ranges):
if self.ranges[i + 1][0] <= self.ranges[i][1] + 1:
self.ranges[i] = (self.ranges[i][0], max(self.ranges[i][1],
self.ranges[i + 1][1]))
del self.ranges[i + 1]
else:
break
i += 1
def extend(self, s):
"""Add ranges from an xperm set
"""
self.ranges.extend(s.ranges)
self.__normalize_ranges()
def add(self, minimum, maximum=None):
"""Add value of range of values to the xperm set.
"""
if maximum is None:
maximum = minimum
self.ranges.append((minimum, maximum))
self.__normalize_ranges()
def to_string(self):
if not self.ranges:
return ""
compl = "~ " if self.complement else ""
# print single value without braces
if len(self.ranges) == 1 and self.ranges[0][0] == self.ranges[0][1]:
return compl + str(self.ranges[0][0])
vals = map(lambda x: str(x[0]) if x[0] == x[1] else "%s-%s" % x,
self.ranges)
return "%s{ %s }" % (compl, " ".join(vals))
# Basic statements
class TypeAttribute(Leaf):
@ -467,8 +534,10 @@ class AVRule(Leaf):
return "allow"
elif self.rule_type == self.DONTAUDIT:
return "dontaudit"
else:
elif self.rule_type == self.AUDITALLOW:
return "auditallow"
elif self.rule_type == self.NEVERALLOW:
return "neverallow"
def from_av(self, av):
"""Add the access from an access vector to this allow
@ -492,6 +561,65 @@ class AVRule(Leaf):
self.tgt_types.to_space_str(),
self.obj_classes.to_space_str(),
self.perms.to_space_str())
class AVExtRule(Leaf):
"""Extended permission access vector rule.
The AVExtRule class represents allowxperm, dontauditxperm,
auditallowxperm, and neverallowxperm rules.
The source and target types, and object classes are represented
by sets containing strings. The operation is a single string,
e.g. 'ioctl'. Extended permissions are represented by an XpermSet.
"""
ALLOWXPERM = 0
DONTAUDITXPERM = 1
AUDITALLOWXPERM = 2
NEVERALLOWXPERM = 3
def __init__(self, av=None, op=None, parent=None):
Leaf.__init__(self, parent)
self.src_types = IdSet()
self.tgt_types = IdSet()
self.obj_classes = IdSet()
self.rule_type = self.ALLOWXPERM
self.xperms = XpermSet()
self.operation = op
if av:
self.from_av(av, op)
def __rule_type_str(self):
if self.rule_type == self.ALLOWXPERM:
return "allowxperm"
elif self.rule_type == self.DONTAUDITXPERM:
return "dontauditxperm"
elif self.rule_type == self.AUDITALLOWXPERM:
return "auditallowxperm"
elif self.rule_type == self.NEVERALLOWXPERM:
return "neverallowxperm"
def from_av(self, av, op):
self.src_types.add(av.src_type)
if av.src_type == av.tgt_type:
self.tgt_types.add("self")
else:
self.tgt_types.add(av.tgt_type)
self.obj_classes.add(av.obj_class)
self.operation = op
self.xperms = av.xperms[op]
def to_string(self):
"""Return a string representation of the rule that is
a valid policy language representation (assuming that
the types, object class, etc. are valid).
"""
return "%s %s %s:%s %s %s;" % (self.__rule_type_str(),
self.src_types.to_space_str(),
self.tgt_types.to_space_str(),
self.obj_classes.to_space_str(),
self.operation,
self.xperms.to_string())
class TypeRule(Leaf):
"""SELinux type rules.

View file

@ -32,6 +32,7 @@ class TestAccessVector(unittest.TestCase):
self.assertEqual(a.obj_class, None)
self.assertTrue(isinstance(a.perms, refpolicy.IdSet))
self.assertTrue(isinstance(a.audit_msgs, type([])))
self.assertTrue(isinstance(a.xperms, type({})))
self.assertEqual(len(a.audit_msgs), 0)
# Construction from a list
@ -61,6 +62,10 @@ class TestAccessVector(unittest.TestCase):
self.assertEqual(a.obj_class, l.obj_class)
self.assertEqual(a.perms, l.perms)
l2 = access.AccessVector()
with self.assertRaises(ValueError):
l2.from_list(['foo', 'bar', 'file'])
def test_to_list(self):
a = access.AccessVector()
a.src_type = "foo"
@ -145,7 +150,80 @@ class TestAccessVector(unittest.TestCase):
b.perms = refpolicy.IdSet(["read", "append"])
self.assertNotEqual(a, b)
def test_merge_noxperm(self):
"""Test merging two AVs without xperms"""
a = access.AccessVector(["foo", "bar", "file", "read", "write"])
b = access.AccessVector(["foo", "bar", "file", "append"])
a.merge(b)
self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
def text_merge_xperm1(self):
"""Test merging AV that contains xperms with AV that does not"""
a = access.AccessVector(["foo", "bar", "file", "read"])
b = access.AccessVector(["foo", "bar", "file", "read"])
xp = refpolicy.XpermSet()
xp.add(42)
xp.add(12345)
b.xperms = {"ioctl": xp}
a.merge(b)
self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
self.assertEqual(list(a.xperms.keys()), ["ioctl"])
self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
def text_merge_xperm2(self):
"""Test merging AV that does not contain xperms with AV that does"""
a = access.AccessVector(["foo", "bar", "file", "read"])
xp = refpolicy.XpermSet()
xp.add(42)
xp.add(12345)
a.xperms = {"ioctl": xp}
b = access.AccessVector(["foo", "bar", "file", "read"])
a.merge(b)
self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
self.assertEqual(list(a.xperms.keys()), ["ioctl"])
self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
def test_merge_xperm_diff_op(self):
"""Test merging two AVs that contain xperms with different operation"""
a = access.AccessVector(["foo", "bar", "file", "read"])
xp1 = refpolicy.XpermSet()
xp1.add(23)
a.xperms = {"asdf": xp1}
b = access.AccessVector(["foo", "bar", "file", "read"])
xp2 = refpolicy.XpermSet()
xp2.add(42)
xp2.add(12345)
b.xperms = {"ioctl": xp2}
a.merge(b)
self.assertEqual(list(a.perms), ["read"])
self.assertEqual(sorted(list(a.xperms.keys())), ["asdf", "ioctl"])
self.assertEqual(a.xperms["asdf"].to_string(), "23")
self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
def test_merge_xperm_same_op(self):
"""Test merging two AVs that contain xperms with same operation"""
a = access.AccessVector(["foo", "bar", "file", "read"])
xp1 = refpolicy.XpermSet()
xp1.add(23)
a.xperms = {"ioctl": xp1}
b = access.AccessVector(["foo", "bar", "file", "read"])
xp2 = refpolicy.XpermSet()
xp2.add(42)
xp2.add(12345)
b.xperms = {"ioctl": xp2}
a.merge(b)
self.assertEqual(list(a.perms), ["read"])
self.assertEqual(list(a.xperms.keys()), ["ioctl"])
self.assertEqual(a.xperms["ioctl"].to_string(), "{ 23 42 12345 }")
class TestUtilFunctions(unittest.TestCase):
def test_is_idparam(self):
self.assertTrue(access.is_idparam("$1"))
@ -260,3 +338,53 @@ class TestAccessVectorSet(unittest.TestCase):
b = access.AccessVectorSet()
b.from_list(avl)
self.assertEqual(len(b), 3)
def test_add_av_first(self):
"""Test adding first AV to the AV set"""
avs = access.AccessVectorSet()
av = access.AccessVector(['foo', 'bar', 'file', 'read'])
avs.add_av(av)
self.assertEqual(avs.to_list(), [['foo', 'bar', 'file', 'read']])
def test_add_av_second(self):
"""Test adding second AV to the AV set with same source and target
context and class"""
avs = access.AccessVectorSet()
av1 = access.AccessVector(['foo', 'bar', 'file', 'read'])
av2 = access.AccessVector(['foo', 'bar', 'file', 'write'])
avs.add_av(av1)
avs.add_av(av2)
self.assertEqual(avs.to_list(), [['foo', 'bar', 'file', 'read',
'write']])
def test_add_av_with_msg(self):
"""Test adding audit message"""
avs = access.AccessVectorSet()
av = access.AccessVector(['foo', 'bar', 'file', 'read'])
avs.add_av(av, 'test message')
self.assertEqual(avs.src['foo']['bar']['file', av.type].audit_msgs,
['test message'])
def test_add(self):
"""Test adding AV to the set"""
s = access.AccessVectorSet()
def test_add_av(av, audit_msg=None):
self.assertEqual(av.src_type, 'foo')
self.assertEqual(av.tgt_type, 'bar')
self.assertEqual(av.obj_class, 'file')
self.assertEqual(list(av.perms), ['read'])
self.assertEqual(av.data, 'test data')
self.assertEqual(av.type, 42)
self.assertEqual(audit_msg, 'test message')
s.add_av = test_add_av
s.add("foo", "bar", "file", refpolicy.IdSet(["read"]),
audit_msg='test message', avc_type=42, data='test data')

View file

@ -56,6 +56,18 @@ type=SYSCALL msg=audit(1162852201.019:1225): arch=40000003 syscall=11 success=ye
type=AVC msg=audit(1162852201.019:1225): avc: denied { execute_no_trans } for pid=6974 comm="sh" name="sa1" dev=dm-0 ino=13061698 scontext=system_u:system_r:crond_t:s0-s0:c0.c1023 tcontext=system_u:object_r:lib_t:s0 tclass=file
type=AVC msg=audit(1162852201.019:1225): avc: denied { execute } for pid=6974 comm="sh" name="sa1" dev=dm-0 ino=13061698 scontext=system_u:system_r:crond_t:s0-s0:c0.c1023 tcontext=system_u:object_r:lib_t:s0 tclass=file"""
xperms1 = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x42 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
"""
xperms2 = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x42 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x1234 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0xdead scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
type=AVC msg=audit(1516626657.910:4461): avc: denied { getattr } for pid=4310 comm="test" path="/root/test" ino=8619937 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=dir permissive=0
"""
xperms_invalid = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=asdf scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
"""
xperms_without = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
"""
class TestAVCMessage(unittest.TestCase):
def test_defs(self):
avc = sepolgen.audit.AVCMessage(audit1)
@ -64,6 +76,7 @@ class TestAVCMessage(unittest.TestCase):
self.assertEqual(avc.tcontext, sc)
self.assertEqual(avc.tclass, "")
self.assertEqual(avc.accesses, [])
self.assertEqual(avc.ioctlcmd, None)
def test_granted(self):
avc = sepolgen.audit.AVCMessage(granted1)
@ -84,6 +97,29 @@ class TestAVCMessage(unittest.TestCase):
self.assertEqual(avc.denial, False)
def test_xperms(self):
"""Test that the ioctlcmd field is parsed"""
avc = sepolgen.audit.AVCMessage(xperms1)
recs = xperms1.split()
avc.from_split_string(recs)
self.assertEqual(avc.ioctlcmd, 66)
def test_xperms_invalid(self):
"""Test message with invalid value in the ioctlcmd field"""
avc = sepolgen.audit.AVCMessage(xperms_invalid)
recs = xperms_invalid.split()
avc.from_split_string(recs)
self.assertIsNone(avc.ioctlcmd)
def test_xperms_without(self):
"""Test message without the ioctlcmd field"""
avc = sepolgen.audit.AVCMessage(xperms_without)
recs = xperms_without.split()
avc.from_split_string(recs)
self.assertIsNone(avc.ioctlcmd)
def test_from_split_string(self):
# syslog message
@ -172,6 +208,20 @@ class TestAuditParser(unittest.TestCase):
self.assertEqual(len(a.invalid_msgs), 0)
self.assertEqual(len(a.policy_load_msgs), 0)
def test_parse_xperms(self):
""" Test that correct access vectors are generated from a set of AVC
denial messages. """
a = sepolgen.audit.AuditParser()
a.parse_string(xperms2)
av_set = a.to_access()
self.assertEqual(len(av_set), 2)
av_list = list(sorted(av_set))
self.assertEqual(av_list[0].xperms, {})
self.assertEqual(list(av_list[1].xperms), ["ioctl"])
self.assertEqual(av_list[1].xperms["ioctl"].ranges, [(66,66),
(4660,4660), (57005,57005)])
class TestGeneration(unittest.TestCase):
def test_generation(self):
parser = sepolgen.audit.AuditParser()

View file

@ -19,13 +19,117 @@
import unittest
import sepolgen.policygen as policygen
import sepolgen.access as access
import sepolgen.refpolicy as refpolicy
class PolicyGenerator(unittest.TestCase):
def __init__(self):
g = policygen.PolicyGenerator()
class TestPolicyGenerator(unittest.TestCase):
def setUp(self):
self.g = policygen.PolicyGenerator()
def test_init(self):
""" Test that extended permission AV rules are not generated by
default. """
self.assertFalse(self.g.xperms)
def test_set_gen_xperms(self):
""" Test turning on and off generating of extended permission
AV rules. """
self.g.set_gen_xperms(True)
self.assertTrue(self.g.xperms)
self.g.set_gen_xperms(False)
self.assertFalse(self.g.xperms)
def test_av_rules(self):
""" Test generating of AV rules from access vectors. """
av1 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
av2 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "open"])
av3 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "read"])
avs = access.AccessVectorSet()
avs.add_av(av1)
avs.add_av(av2)
avs.add_av(av3)
self.g.add_access(avs)
self.assertEqual(len(self.g.module.children), 1)
r = self.g.module.children[0]
self.assertIsInstance(r, refpolicy.AVRule)
self.assertEqual(r.to_string(),
"allow test_src_t test_tgt_t:file { ioctl open read };")
def test_ext_av_rules(self):
""" Test generating of extended permission AV rules from access
vectors. """
self.g.set_gen_xperms(True)
av1 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
av1.xperms['ioctl'] = refpolicy.XpermSet()
av1.xperms['ioctl'].add(42)
av2 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
av2.xperms['ioctl'] = refpolicy.XpermSet()
av2.xperms['ioctl'].add(1234)
av3 = access.AccessVector(["test_src_t", "test_tgt_t", "dir", "ioctl"])
av3.xperms['ioctl'] = refpolicy.XpermSet()
av3.xperms['ioctl'].add(2345)
avs = access.AccessVectorSet()
avs.add_av(av1)
avs.add_av(av2)
avs.add_av(av3)
self.g.add_access(avs)
self.assertEqual(len(self.g.module.children), 4)
# we cannot sort the rules, so find all rules manually
av_rule1 = av_rule2 = av_ext_rule1 = av_ext_rule2 = None
for r in self.g.module.children:
if isinstance(r, refpolicy.AVRule):
if 'file' in r.obj_classes:
av_rule1 = r
else:
av_rule2 = r
elif isinstance(r, refpolicy.AVExtRule):
if 'file' in r.obj_classes:
av_ext_rule1 = r
else:
av_ext_rule2 = r
else:
self.fail("Unexpected rule type '%s'" % type(r))
# check that all rules are present
self.assertNotIn(None, (av_rule1, av_rule2, av_ext_rule1, av_ext_rule2))
self.assertEqual(av_rule1.rule_type, av_rule1.ALLOW)
self.assertEqual(av_rule1.src_types, {"test_src_t"})
self.assertEqual(av_rule1.tgt_types, {"test_tgt_t"})
self.assertEqual(av_rule1.obj_classes, {"file"})
self.assertEqual(av_rule1.perms, {"ioctl"})
self.assertEqual(av_ext_rule1.rule_type, av_ext_rule1.ALLOWXPERM)
self.assertEqual(av_ext_rule1.src_types, {"test_src_t"})
self.assertEqual(av_ext_rule1.tgt_types, {"test_tgt_t"})
self.assertEqual(av_ext_rule1.obj_classes, {"file"})
self.assertEqual(av_ext_rule1.operation, "ioctl")
xp1 = refpolicy.XpermSet()
xp1.add(42)
xp1.add(1234)
self.assertEqual(av_ext_rule1.xperms.ranges, xp1.ranges)
self.assertEqual(av_rule2.rule_type, av_rule2.ALLOW)
self.assertEqual(av_rule2.src_types, {"test_src_t"})
self.assertEqual(av_rule2.tgt_types, {"test_tgt_t"})
self.assertEqual(av_rule2.obj_classes, {"dir"})
self.assertEqual(av_rule2.perms, {"ioctl"})
self.assertEqual(av_ext_rule2.rule_type, av_ext_rule2.ALLOWXPERM)
self.assertEqual(av_ext_rule2.src_types, {"test_src_t"})
self.assertEqual(av_ext_rule2.tgt_types, {"test_tgt_t"})
self.assertEqual(av_ext_rule2.obj_classes, {"dir"})
self.assertEqual(av_ext_rule2.operation, "ioctl")
xp2 = refpolicy.XpermSet()
xp2.add(2345)
self.assertEqual(av_ext_rule2.xperms.ranges, xp2.ranges)

View file

@ -19,6 +19,7 @@
import unittest
import sepolgen.refpolicy as refpolicy
import sepolgen.access as access
import selinux
class TestIdSet(unittest.TestCase):
@ -33,6 +34,74 @@ class TestIdSet(unittest.TestCase):
s.add("read")
self.assertEqual(s.to_space_str(), "read")
class TestXpermSet(unittest.TestCase):
def test_init(self):
""" Test that all atttributes are correctly initialized. """
s1 = refpolicy.XpermSet()
self.assertEqual(s1.complement, False)
self.assertEqual(s1.ranges, [])
s2 = refpolicy.XpermSet(True)
self.assertEqual(s2.complement, True)
self.assertEqual(s2.ranges, [])
def test_normalize_ranges(self):
""" Test that ranges that are overlapping or neighboring are correctly
merged into one range. """
s = refpolicy.XpermSet()
s.ranges = [(1, 7), (5, 10), (100, 110), (102, 107), (200, 205),
(205, 210), (300, 305), (306, 310), (400, 405), (407, 410),
(500, 502), (504, 508), (500, 510)]
s._XpermSet__normalize_ranges()
i = 0
r = list(sorted(s.ranges))
while i < len(r) - 1:
# check that range low bound is less than equal than the upper bound
self.assertLessEqual(r[i][0], r[i][1])
# check that two ranges are not overlapping or neighboring
self.assertGreater(r[i + 1][0] - r[i][1], 1)
i += 1
def test_add(self):
""" Test adding new values or ranges to the set. """
s = refpolicy.XpermSet()
s.add(1, 7)
s.add(5, 10)
s.add(42)
self.assertEqual(s.ranges, [(1,10), (42,42)])
def test_extend(self):
""" Test adding ranges from another XpermSet object. """
a = refpolicy.XpermSet()
a.add(1, 7)
b = refpolicy.XpermSet()
b.add(5, 10)
a.extend(b)
self.assertEqual(a.ranges, [(1,10)])
def test_to_string(self):
""" Test printing the values to a string. """
a = refpolicy.XpermSet()
a.complement = False
self.assertEqual(a.to_string(), "")
a.complement = True
self.assertEqual(a.to_string(), "")
a.add(1234)
self.assertEqual(a.to_string(), "~ 1234")
a.complement = False
self.assertEqual(a.to_string(), "1234")
a.add(2345)
self.assertEqual(a.to_string(), "{ 1234 2345 }")
a.complement = True
self.assertEqual(a.to_string(), "~ { 1234 2345 }")
a.add(42,64)
self.assertEqual(a.to_string(), "~ { 42-64 1234 2345 }")
a.complement = False
self.assertEqual(a.to_string(), "{ 42-64 1234 2345 }")
class TestSecurityContext(unittest.TestCase):
def test_init(self):
sc = refpolicy.SecurityContext()
@ -110,6 +179,76 @@ class TestAVRule(unittest.TestCase):
b.sort()
self.assertEqual(a, b)
class TestAVExtRule(unittest.TestCase):
def test_init(self):
""" Test initialization of attributes """
a = refpolicy.AVExtRule()
self.assertEqual(a.rule_type, a.ALLOWXPERM)
self.assertIsInstance(a.src_types, set)
self.assertIsInstance(a.tgt_types, set)
self.assertIsInstance(a.obj_classes, set)
self.assertIsNone(a.operation)
self.assertIsInstance(a.xperms, refpolicy.XpermSet)
def test_rule_type_str(self):
""" Test strings returned by __rule_type_str() """
a = refpolicy.AVExtRule()
self.assertEqual(a._AVExtRule__rule_type_str(), "allowxperm")
a.rule_type = a.ALLOWXPERM
self.assertEqual(a._AVExtRule__rule_type_str(), "allowxperm")
a.rule_type = a.DONTAUDITXPERM
self.assertEqual(a._AVExtRule__rule_type_str(), "dontauditxperm")
a.rule_type = a.NEVERALLOWXPERM
self.assertEqual(a._AVExtRule__rule_type_str(), "neverallowxperm")
a.rule_type = a.AUDITALLOWXPERM
self.assertEqual(a._AVExtRule__rule_type_str(), "auditallowxperm")
a.rule_type = 42
self.assertIsNone(a._AVExtRule__rule_type_str())
def test_from_av(self):
""" Test creating the rule from an access vector. """
av = access.AccessVector(["foo", "bar", "file", "ioctl"])
xp = refpolicy.XpermSet()
av.xperms = { "ioctl": xp }
a = refpolicy.AVExtRule()
a.from_av(av, "ioctl")
self.assertEqual(a.src_types, {"foo"})
self.assertEqual(a.tgt_types, {"bar"})
self.assertEqual(a.obj_classes, {"file"})
self.assertEqual(a.operation, "ioctl")
self.assertIs(a.xperms, xp)
def test_from_av_self(self):
""" Test creating the rule from an access vector that has same
source and target context. """
av = access.AccessVector(["foo", "foo", "file", "ioctl"])
xp = refpolicy.XpermSet()
av.xperms = { "ioctl": xp }
a = refpolicy.AVExtRule()
a.from_av(av, "ioctl")
self.assertEqual(a.src_types, {"foo"})
self.assertEqual(a.tgt_types, {"self"})
self.assertEqual(a.obj_classes, {"file"})
self.assertEqual(a.operation, "ioctl")
self.assertIs(a.xperms, xp)
def test_to_string(self):
""" Test printing the rule to a string. """
a = refpolicy.AVExtRule()
a._AVExtRule__rule_type_str = lambda: "first"
a.src_types.to_space_str = lambda: "second"
a.tgt_types.to_space_str = lambda: "third"
a.obj_classes.to_space_str = lambda: "fourth"
a.operation = "fifth"
a.xperms.to_string = lambda: "seventh"
self.assertEqual(a.to_string(),
"first second third:fourth fifth seventh;")
class TestTypeRule(unittest.TestCase):
def test_init(self):
a = refpolicy.TypeRule()

View file

@ -31,7 +31,7 @@ List all interfaces
List all domains with SELinux user role interface
.TP
.I \-v, \-\-verbose
Display extended information about the interface including parameters and desctiprion if available.
Display extended information about the interface including parameters and description if available.
.SH "AUTHOR"
This man page was written by Daniel Walsh <dwalsh@redhat.com>

View file

@ -10,4 +10,4 @@ SELinux Systems can boot in three different modes.
You can use this screen to change the enforcing mode.
Note if you disable SELinux, you will need to to reboot, to turn it off. Also the next time you turn SELinux on, a full system relabel will be performed.
Note if you disable SELinux, you will need to reboot, to turn it off. Also the next time you turn SELinux on, a full system relabel will be performed.

View file

@ -1283,7 +1283,7 @@ USERNAME ALL=(ALL) ROLE=%(user)s_r TYPE=%(user)s_t COMMAND
.br
sudo will run COMMAND as staff_u:%(user)s_r:%(user)s_t:LEVEL
When using a a non login role, you need to setup SELinux so that your SELinux user can reach %(user)s_r role.
When using a non login role, you need to setup SELinux so that your SELinux user can reach %(user)s_r role.
Execute the following to see all of the assigned SELinux roles:

View file

@ -9,8 +9,8 @@ DBUSSERVICEDIR = $(PREFIX)/share/dbus-1/services
SYSTEMDDIR ?= $(PREFIX)/lib/systemd
autostart_DATA = sealertauto.desktop
INITDIR ?= $(DESTDIR)/etc/rc.d/init.d
SELINUXDIR = $(DESTDIR)/etc/selinux
INITDIR ?= /etc/rc.d/init.d
SELINUXDIR = /etc/selinux
DBUSFLAGS = -DHAVE_DBUS $(shell $(PKG_CONFIG) --cflags dbus-glib-1)
DBUSLIB = $(shell $(PKG_CONFIG) --libs dbus-glib-1)
@ -42,11 +42,11 @@ install: all
-mkdir -p $(DESTDIR)$(SBINDIR)
install -m 755 restorecond $(DESTDIR)$(SBINDIR)
install -m 644 restorecond.8 $(DESTDIR)$(MANDIR)/man8
-mkdir -p $(INITDIR)
install -m 755 restorecond.init $(INITDIR)/restorecond
-mkdir -p $(SELINUXDIR)
install -m 644 restorecond.conf $(SELINUXDIR)/restorecond.conf
install -m 644 restorecond_user.conf $(SELINUXDIR)/restorecond_user.conf
-mkdir -p $(DESTDIR)$(INITDIR)
install -m 755 restorecond.init $(DESTDIR)$(INITDIR)/restorecond
-mkdir -p $(DESTDIR)$(SELINUXDIR)
install -m 644 restorecond.conf $(DESTDIR)$(SELINUXDIR)/restorecond.conf
install -m 644 restorecond_user.conf $(DESTDIR)$(SELINUXDIR)/restorecond_user.conf
-mkdir -p $(DESTDIR)$(AUTOSTARTDIR)
install -m 644 restorecond.desktop $(DESTDIR)$(AUTOSTARTDIR)/restorecond.desktop
-mkdir -p $(DESTDIR)$(DBUSSERVICEDIR)

View file

@ -1 +1 @@
2.7
2.8

View file

@ -1,11 +1,14 @@
/*
* Note that the restorecond(8) service build links with these functions.
* Therefore any changes here should also be tested against that utility.
*/
#include "restore.h"
#include <glob.h>
#ifndef GLOB_TILDE
#define GLOB_TILDE 0
#endif
#ifndef GLOB_BRACE
#define GLOB_BRACE 0
#endif
char **exclude_list;
int exclude_count;

View file

@ -105,6 +105,7 @@ static int write_pid_file(void)
}
if (write(pidfd, val, (unsigned int)len) != len) {
syslog(LOG_ERR, "Unable to write to pidfile (%s)", strerror(errno));
close(pidfd);
return 1;
}
close(pidfd);

View file

@ -20,6 +20,14 @@
#include "stringslist.h"
#include "utmpwatcher.h"
#ifndef GLOB_TILDE
#define GLOB_TILDE 0
#endif
#ifndef GLOB_BRACE
#define GLOB_BRACE 0
#endif
/* size of the event structure, not counting name */
#define EVENT_SIZE (sizeof (struct inotify_event))
/* reasonable guess as to size of 1024 events */

View file

@ -1 +1 @@
2.7
2.8

View file

@ -16,7 +16,7 @@ within the specified context, using the alternate home directory and /tmp direct
Alternate homedir to be used by the application. Homedir must be owned by the user.
.TP
\fB\-t\ tmpdir
Use alternate tempory directory to mount on /tmp. tmpdir must be owned by the user.
Use alternate temporary directory to mount on /tmp. tmpdir must be owned by the user.
.TP
\fB\-C --capabilities\fR
Allow apps executed within the namespace to use capabilities. Default is no capabilities.

1
scripts/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/output-scan-build/

33
scripts/run-scan-build Executable file
View file

@ -0,0 +1,33 @@
#!/bin/sh
# Run clang's static analyzer (scan-build) and record its output in output-scan-build/
# Ensure the current directory is where this script is
cd "$(dirname -- "$0")" || exit $?
OUTPUTDIR="$(pwd)/output-scan-build"
# Display the commands which are run, and make sure they succeed
set -x -e
# Use a temporary directory as an installation directory, if $DESTDIR is not set
if [ -z "$DESTDIR" ] ; then
DESTDIR="$(mktemp --tmpdir -d scan-build-destdir-XXXXXXXXXX)"
fi
# Make sure to use the newly-installed libraries when running tests
export LD_LIBRARY_PATH="$DESTDIR/usr/lib:$DESTDIR/lib"
export PATH="$DESTDIR/usr/sbin:$DESTDIR/usr/bin:$DESTDIR/sbin:$DESTDIR/bin:$PATH"
export PYTHONPATH="$DESTDIR$(${PYTHON:-python} -c "from distutils.sysconfig import *;print(get_python_lib(prefix='/usr'))")"
export RUBYLIB="$DESTDIR/$(${RUBY:-ruby} -e 'puts RbConfig::CONFIG["vendorlibdir"]'):$DESTDIR/$(${RUBY:-ruby} -e 'puts RbConfig::CONFIG["vendorarchdir"]')"
# Build and analyze
make -C .. CC=clang clean distclean -j"$(nproc)"
scan-build -analyze-headers -o "$OUTPUTDIR" make -C .. CC=clang DESTDIR="$DESTDIR" install install-pywrap install-rubywrap all test
# Reduce the verbosity in order to keep the message from scan-build saying
# "scan-build: Run 'scan-view /.../output-scan-build/2018-...' to examine bug reports.
set +x
# Remove the destination directory without using "rm -rf"
chmod u+w "$DESTDIR/usr/bin/newrole"
rm -r "$DESTDIR"

View file

@ -58,6 +58,7 @@ clean:
rm -f file_contexts
rm -f $(SECILC_MANPAGE)
rm -f $(SECIL2CONF_MANPAGE)
$(MAKE) -C docs clean
relabel:

View file

@ -1 +1 @@
2.7
2.8

View file

@ -1 +1 @@
2.7
2.8