mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Merge from apparmor trunk; fixed up conflict due to imported indonesian
.po file.
This commit is contained in:
commit
28f072bfb2
181 changed files with 5512 additions and 941 deletions
15
.bzrignore
15
.bzrignore
|
@ -46,7 +46,10 @@ libraries/libapparmor/ylwrap
|
|||
libraries/libapparmor/doc/Makefile
|
||||
libraries/libapparmor/doc/Makefile.in
|
||||
libraries/libapparmor/doc/*.2
|
||||
libraries/libapparmor/doc/aa_*.3
|
||||
libraries/libapparmor/include/Makefile
|
||||
libraries/libapparmor/include/Makefile.in
|
||||
libraries/libapparmor/include/sys/Makefile
|
||||
libraries/libapparmor/include/sys/Makefile.in
|
||||
libraries/libapparmor/src/.deps
|
||||
libraries/libapparmor/src/.libs
|
||||
|
@ -54,10 +57,16 @@ libraries/libapparmor/src/Makefile
|
|||
libraries/libapparmor/src/Makefile.in
|
||||
libraries/libapparmor/src/af_protos.h
|
||||
libraries/libapparmor/src/change_hat.lo
|
||||
libraries/libapparmor/src/features.lo
|
||||
libraries/libapparmor/src/grammar.lo
|
||||
libraries/libapparmor/src/kernel.lo
|
||||
libraries/libapparmor/src/kernel_interface.lo
|
||||
libraries/libapparmor/src/libaalogparse.lo
|
||||
libraries/libapparmor/src/libimmunix_warning.lo
|
||||
libraries/libapparmor/src/policy_cache.lo
|
||||
libraries/libapparmor/src/private.lo
|
||||
libraries/libapparmor/src/scanner.lo
|
||||
libraries/libapparmor/src/libapparmor.pc
|
||||
libraries/libapparmor/src/libapparmor.la
|
||||
libraries/libapparmor/src/libimmunix.la
|
||||
libraries/libapparmor/src/grammar.c
|
||||
|
@ -74,12 +83,18 @@ libraries/libapparmor/swig/perl/Makefile.PL
|
|||
libraries/libapparmor/swig/perl/Makefile.in
|
||||
libraries/libapparmor/swig/perl/Makefile.perl
|
||||
libraries/libapparmor/swig/perl/Makefile.perle
|
||||
libraries/libapparmor/swig/perl/MYMETA.json
|
||||
libraries/libapparmor/swig/perl/MYMETA.yml
|
||||
libraries/libapparmor/swig/perl/blib
|
||||
libraries/libapparmor/swig/perl/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/perl/pm_to_blib
|
||||
libraries/libapparmor/swig/python/__init__.py
|
||||
libraries/libapparmor/swig/python/build/
|
||||
libraries/libapparmor/swig/python/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/python/Makefile
|
||||
libraries/libapparmor/swig/python/Makefile.in
|
||||
libraries/libapparmor/swig/python/setup.py
|
||||
libraries/libapparmor/swig/python/test/Makefile
|
||||
libraries/libapparmor/swig/python/test/Makefile.in
|
||||
libraries/libapparmor/swig/ruby/Makefile
|
||||
libraries/libapparmor/swig/ruby/Makefile.in
|
||||
|
|
1
Makefile
1
Makefile
|
@ -11,6 +11,7 @@ include ${COMMONDIR}/Make.rules
|
|||
DIRS=parser \
|
||||
profiles \
|
||||
utils \
|
||||
binutils \
|
||||
libraries/libapparmor \
|
||||
changehat/mod_apparmor \
|
||||
changehat/pam_apparmor \
|
||||
|
|
10
README
10
README
|
@ -27,6 +27,7 @@ Source Layout
|
|||
|
||||
AppArmor consists of several different parts:
|
||||
|
||||
binutils/ source for basic utilities written in compiled languages
|
||||
changehat/ source for using changehat with Apache, PAM and Tomcat
|
||||
common/ common makefile rules
|
||||
desktop/ empty
|
||||
|
@ -71,6 +72,13 @@ $ make install
|
|||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
Binary Utilities:
|
||||
$ cd binutils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
|
||||
Utilities:
|
||||
$ cd utils
|
||||
$ make
|
||||
|
@ -104,7 +112,7 @@ $ make check # depends on the parser having been built first
|
|||
$ make install
|
||||
|
||||
|
||||
[Note that for the parser and the utils, if you only with to build/use
|
||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||
some of the locale languages, you can override the default by passing
|
||||
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
||||
|
||||
|
|
157
binutils/Makefile
Normal file
157
binutils/Makefile
Normal file
|
@ -0,0 +1,157 @@
|
|||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2015
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
# ----------------------------------------------------------------------
|
||||
NAME=aa-binutils
|
||||
all:
|
||||
COMMONDIR=../common/
|
||||
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/bin
|
||||
LOCALEDIR=/usr/share/locale
|
||||
MANPAGES=aa-enabled.8 aa-exec.8
|
||||
|
||||
WARNINGS = -Wall
|
||||
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
|
||||
CPP_WARNINGS =
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -g -O2 -pipe
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -pg -D DEBUG
|
||||
endif
|
||||
ifdef COVERAGE
|
||||
CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
||||
#INCLUDEDIR = /usr/src/linux/include
|
||||
INCLUDEDIR =
|
||||
|
||||
ifdef INCLUDEDIR
|
||||
CFLAGS += -I$(INCLUDEDIR)
|
||||
endif
|
||||
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c
|
||||
HDRS =
|
||||
TOOLS = aa-enabled aa-exec
|
||||
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
# Using the system libapparmor so Makefile dependencies can't be used
|
||||
LIBAPPARMOR_A =
|
||||
INCLUDE_APPARMOR =
|
||||
APPARMOR_H =
|
||||
LIBAPPARMOR_LDFLAGS =
|
||||
else
|
||||
LIBAPPARMOR_SRC = ../libraries/libapparmor/
|
||||
LOCAL_LIBAPPARMOR_INCLUDE = $(LIBAPPARMOR_SRC)/include
|
||||
LOCAL_LIBAPPARMOR_LDPATH = $(LIBAPPARMOR_SRC)/src/.libs
|
||||
|
||||
LIBAPPARMOR_A = $(LOCAL_LIBAPPARMOR_LDPATH)/libapparmor.a
|
||||
INCLUDE_APPARMOR = -I$(LOCAL_LIBAPPARMOR_INCLUDE)
|
||||
APPARMOR_H = $(LOCAL_LIBAPPARMOR_INCLUDE)/sys/apparmor.h
|
||||
LIBAPPARMOR_LDFLAGS = -L$(LOCAL_LIBAPPARMOR_LDPATH)
|
||||
endif
|
||||
EXTRA_CFLAGS += $(INCLUDE_APPARMOR)
|
||||
LDFLAGS += $(LIBAPPARMOR_LDFLAGS)
|
||||
|
||||
ifdef V
|
||||
VERBOSE = 1
|
||||
endif
|
||||
ifndef VERBOSE
|
||||
VERBOSE = 0
|
||||
endif
|
||||
ifeq ($(VERBOSE),1)
|
||||
BUILD_OUTPUT =
|
||||
Q =
|
||||
else
|
||||
BUILD_OUTPUT = > /dev/null 2>&1
|
||||
Q = @
|
||||
endif
|
||||
export Q VERBOSE BUILD_OUTPUT
|
||||
|
||||
po/%.pot: %.c
|
||||
$(MAKE) -C po $(@F) NAME=$* SOURCES=$*.c
|
||||
|
||||
# targets arranged this way so that people who don't want full docs can
|
||||
# pick specific targets they want.
|
||||
arch: $(TOOLS)
|
||||
|
||||
manpages: $(MANPAGES)
|
||||
|
||||
docs: manpages
|
||||
|
||||
indep: docs
|
||||
$(Q)$(MAKE) -C po all
|
||||
|
||||
all: arch indep
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(MAKE) clean $(TOOLS) COVERAGE=1
|
||||
|
||||
ifndef USE_SYSTEM
|
||||
$(LIBAPPARMOR_A):
|
||||
@if [ ! -f $@ ]; then \
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
return 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-exec: aa_exec.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
.SILENT: check
|
||||
.PHONY: check
|
||||
check: check_pod_files tests
|
||||
|
||||
.SILENT: tests
|
||||
tests: $(TOOLS) $(TESTS)
|
||||
echo "no tests atm"
|
||||
|
||||
.PHONY: install
|
||||
install: install-indep install-arch
|
||||
|
||||
.PHONY: install-arch
|
||||
install-arch: arch
|
||||
install -m 755 -d ${BINDIR}
|
||||
install -m 755 ${TOOLS} ${BINDIR}
|
||||
|
||||
.PHONY: install-indep
|
||||
install-indep:
|
||||
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
endif
|
||||
.PHONY: clean
|
||||
clean: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
|
||||
rm -f gmon.out
|
||||
rm -f $(TOOLS) $(TESTS)
|
||||
$(MAKE) -s -C po clean
|
||||
|
94
binutils/aa-enabled.pod
Normal file
94
binutils/aa-enabled.pod
Normal file
|
@ -0,0 +1,94 @@
|
|||
# This publication is intellectual property of Canonical Ltd. Its contents
|
||||
# can be duplicated, either in part or in whole, provided that a copyright
|
||||
# label is visibly located on each copy.
|
||||
#
|
||||
# All information found in this book has been compiled with utmost
|
||||
# attention to detail. However, this does not guarantee complete accuracy.
|
||||
# Neither Canonical Ltd, the authors, nor the translators shall be held
|
||||
# liable for possible errors or the consequences thereof.
|
||||
#
|
||||
# Many of the software and hardware descriptions cited in this book
|
||||
# are registered trademarks. All trade names are subject to copyright
|
||||
# restrictions and may be registered trade marks. Canonical Ltd
|
||||
# essentially adheres to the manufacturer's spelling.
|
||||
#
|
||||
# Names of products and trademarks appearing in this book (with or without
|
||||
# specific notation) are likewise subject to trademark and trade protection
|
||||
# laws and may thus fall under copyright restrictions.
|
||||
#
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-enabled - test whether AppArmor is enabled
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-enabled> [options]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-enabled> is used to determine if AppArmor is enabled.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-enabled> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=item -q, --quiet
|
||||
|
||||
Do not output anything to stdout. This option is intended to be used by
|
||||
scripts that simply want to use the exit code to determine if AppArmor is
|
||||
enabled.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
|
||||
Upon exiting, B<aa-enabled> will set its exit status to the following values:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 0:
|
||||
|
||||
if AppArmor is enabled.
|
||||
|
||||
=item 1:
|
||||
|
||||
if AppArmor is not enabled/loaded.
|
||||
|
||||
=item 2:
|
||||
|
||||
intentionally not used as an B<aa-enabled> exit status.
|
||||
|
||||
=item 3:
|
||||
|
||||
if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item 4:
|
||||
|
||||
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
|
||||
|
||||
=item 64:
|
||||
|
||||
if any unexpected error or condition is encountered.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
|
@ -57,10 +57,6 @@ use the current profile name (likely unconfined).
|
|||
use profiles in NAMESPACE. This will result in confinement transitioning
|
||||
to using the new profile namespace.
|
||||
|
||||
=item -f FILE, --file=FILE
|
||||
|
||||
a file or directory containing profiles to load before confining the program.
|
||||
|
||||
=item -i, --immediate
|
||||
|
||||
transition to PROFILE before doing executing I<E<lt>commandE<gt>>. This
|
92
binutils/aa_enabled.c
Normal file
92
binutils/aa_enabled.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
void print_help(const char *command)
|
||||
{
|
||||
printf(_("%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"),
|
||||
command);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Exit statuses and meanings are documented in the aa-enabled.pod file */
|
||||
static void exit_with_error(int saved_errno, int quiet)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch(saved_errno) {
|
||||
case ENOSYS:
|
||||
if (!quiet)
|
||||
printf(_("No - not available on this system.\n"));
|
||||
exit(1);
|
||||
case ECANCELED:
|
||||
if (!quiet)
|
||||
printf(_("No - disabled at boot.\n"));
|
||||
exit(1);
|
||||
case ENOENT:
|
||||
if (!quiet)
|
||||
printf(_("Maybe - policy interface not available.\n"));
|
||||
exit(3);
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
if (!quiet)
|
||||
printf(_("Maybe - insufficient permissions to determine availability.\n"));
|
||||
exit(4);
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
printf(_("Error - %s\n"), strerror(saved_errno));
|
||||
exit(64);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int enabled;
|
||||
int quiet = 0;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc > 2) {
|
||||
printf(_("unknown or incompatible options\n"));
|
||||
print_help(argv[0]);
|
||||
} else if (argc == 2) {
|
||||
if (strcmp(argv[1], "--quiet") == 0 ||
|
||||
strcmp(argv[1], "-q") == 0) {
|
||||
quiet = 1;
|
||||
} else if (strcmp(argv[1], "--help") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else {
|
||||
printf(_("unknown option '%s'\n"), argv[1]);
|
||||
print_help(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
enabled = aa_is_enabled();
|
||||
if (!enabled)
|
||||
exit_with_error(errno, quiet);
|
||||
|
||||
if (!quiet)
|
||||
printf(_("Yes\n"));
|
||||
exit(0);
|
||||
}
|
218
binutils/aa_exec.c
Normal file
218
binutils/aa_exec.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (c) 2015
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Novell, Inc. or Canonical
|
||||
* Ltd.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
static const char *opt_profile = NULL;
|
||||
static const char *opt_namespace = NULL;
|
||||
static bool opt_debug = false;
|
||||
static bool opt_immediate = false;
|
||||
static bool opt_verbose = false;
|
||||
|
||||
static void usage(const char *name, bool error)
|
||||
{
|
||||
FILE *stream = stdout;
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
if (error) {
|
||||
stream = stderr;
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stream,
|
||||
_("USAGE: %s [OPTIONS] <prog> <args>\n"
|
||||
"\n"
|
||||
"Confine <prog> with the specified PROFILE.\n"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
" -p PROFILE, --profile=PROFILE PROFILE to confine <prog> with\n"
|
||||
" -n NAMESPACE, --namespace=NAMESPACE NAMESPACE to confine <prog> in\n"
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -i, --immediate change profile immediately instead of at exec\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
" -h, --help display this help\n"
|
||||
"\n"), name);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("aa-exec: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define debug(fmt, args...) _debug(_("aa-exec: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_debug)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void verbose_print_argv(char **argv)
|
||||
{
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
fprintf(stderr, _("exec"));
|
||||
for (; *argv; argv++)
|
||||
fprintf(stderr, " %s", *argv);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static char **parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
struct option long_opts[] = {
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"profile", required_argument, 0, 'p'},
|
||||
{"namespace", required_argument, 0, 'n'},
|
||||
{"immediate", no_argument, 0, 'i'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dhp:n:iv", long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], false);
|
||||
break;
|
||||
case 'p':
|
||||
opt_profile = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
opt_namespace = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
opt_immediate = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
usage(argv[0], true);
|
||||
|
||||
return argv + optind;
|
||||
}
|
||||
|
||||
static void build_name(char *name, size_t name_len,
|
||||
const char *namespace, const char *profile)
|
||||
{
|
||||
size_t required_len = 1; /* reserve 1 byte for NUL-terminator */
|
||||
|
||||
if (namespace)
|
||||
required_len += 1 + strlen(namespace) + 3; /* :<NAMESPACE>:// */
|
||||
|
||||
if (profile)
|
||||
required_len += strlen(profile);
|
||||
|
||||
if (required_len > name_len)
|
||||
error("name too long (%zu > %zu)", required_len, name_len);
|
||||
|
||||
name[0] = '\0';
|
||||
|
||||
if (namespace) {
|
||||
strcat(name, ":");
|
||||
strcat(name, namespace);
|
||||
strcat(name, "://");
|
||||
}
|
||||
|
||||
if (profile)
|
||||
strcat(name, profile);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
int rc = 0;
|
||||
|
||||
argv = parse_args(argc, argv);
|
||||
|
||||
if (opt_namespace || opt_profile)
|
||||
build_name(name, sizeof(name), opt_namespace, opt_profile);
|
||||
else
|
||||
goto exec;
|
||||
|
||||
if (opt_immediate) {
|
||||
verbose("aa_change_profile(\"%s\")", name);
|
||||
rc = aa_change_profile(name);
|
||||
debug("%d = aa_change_profile(\"%s\")", rc, name);
|
||||
} else {
|
||||
verbose("aa_change_onexec(\"%s\")", name);
|
||||
rc = aa_change_onexec(name);
|
||||
debug("%d = aa_change_onexec(\"%s\")", rc, name);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
if (errno == ENOENT || errno == EACCES) {
|
||||
error("%s '%s' does not exist\n",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EINVAL) {
|
||||
error("AppArmor interface not available");
|
||||
} else {
|
||||
error("%m");
|
||||
}
|
||||
}
|
||||
|
||||
exec:
|
||||
verbose_print_argv(argv);
|
||||
execvp(argv[0], argv);
|
||||
error("Failed to execute \"%s\": %m", argv[0]);
|
||||
}
|
19
binutils/po/Makefile
Normal file
19
binutils/po/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2015 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
# ----------------------------------------------------------------------
|
||||
all:
|
||||
|
||||
# As translations get added, they will automatically be included, unless
|
||||
# the lang is explicitly added to DISABLED_LANGS; e.g. DISABLED_LANGS=en es
|
||||
|
||||
DISABLED_LANGS=
|
||||
|
||||
COMMONDIR=../../common
|
||||
include $(COMMONDIR)/Make-po.rules
|
||||
|
||||
XGETTEXT_ARGS+=--language=C --keyword=_ $(shell if [ -f ${NAME}.pot ] ; then echo -n -j ; fi)
|
||||
|
66
binutils/po/aa-enabled.pot
Normal file
66
binutils/po/aa-enabled.pot
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Copyright (C) 2015 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2015.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
|
@ -16,6 +16,7 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-01-21 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17886)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 1999-2008 NOVELL (All rights reserved)
|
||||
# Copyright 2009-2010 Canonical Ltd.
|
||||
# Copyright 2009-2015 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
|
@ -21,7 +21,7 @@
|
|||
# exist
|
||||
LOCALEDIR=/usr/share/locale
|
||||
|
||||
XGETTEXT_ARGS=--copyright-holder="NOVELL, Inc." --msgid-bugs-address=apparmor@lists.ubuntu.com -d ${NAME}
|
||||
XGETTEXT_ARGS=--copyright-holder="Canonical Ltd" --msgid-bugs-address=apparmor@lists.ubuntu.com -d ${NAME}
|
||||
|
||||
# When making the .pot file, it's expected that the parent Makefile will
|
||||
# pass in the list of sources in the SOURCES variable
|
||||
|
|
|
@ -82,7 +82,7 @@ pod_clean:
|
|||
# =====================
|
||||
|
||||
# emits defined capabilities in a simple list, e.g. "CAP_NAME CAP_NAME2"
|
||||
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | sort)
|
||||
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | LC_ALL=C sort)
|
||||
|
||||
.PHONY: list_capabilities
|
||||
list_capabilities: /usr/include/linux/capability.h
|
||||
|
|
|
@ -1 +1 @@
|
|||
2.9.90
|
||||
2.10.90
|
||||
|
|
Binary file not shown.
|
@ -24,27 +24,23 @@
|
|||
|
||||
aa_query_label - query access permission associated with a label
|
||||
|
||||
aa_query_file_path, aa_query_file_path_len - query access permissions of a file path
|
||||
|
||||
aa_query_link_path, aa_query_link_path_len - query access permissions of a link path
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<#include E<lt>sys/apparmor.hE<gt>>
|
||||
|
||||
B<int aa_query_label((uint32_t mask, char *query, size_t size,
|
||||
int *allowed, int *audited);>
|
||||
B<int aa_query_label(uint32_t mask, char *query, size_t size, int *allowed, int *audited);>
|
||||
|
||||
B<int aa_query_file_path((uint32_t mask, const char *label, size_t label_len,
|
||||
const char *path, int *allowed, int *audited);>
|
||||
B<int aa_query_file_path(uint32_t mask, const char *label, size_t label_len, const char *path, int *allowed, int *audited);>
|
||||
|
||||
B<int aa_query_file_path_len((uint32_t mask, const char *label,
|
||||
size_t label_len, const char *path, size_t path_len,
|
||||
int *allowed, int *audited);>
|
||||
B<int aa_query_file_path_len(uint32_t mask, const char *label, size_t label_len, const char *path, size_t path_len, int *allowed, int *audited);>
|
||||
|
||||
B<int aa_query_link_path_len(const char *label, size_t label_len,
|
||||
const char *target, size_t target_len,
|
||||
const char *link, size_t link_len,
|
||||
int *allowed, int *audited);>
|
||||
B<int aa_query_link_path(const char *label, const char *target, const char *link, int *allowed, int *audited);>
|
||||
|
||||
B<int aa_query_link_path(const char *label, const char *target,
|
||||
const char *link, int *allowed, int *audited);>
|
||||
B<int aa_query_link_path_len(const char *label, size_t label_len, const char *target, size_t target_len, const char *link, size_t link_len, int *allowed, int *audited);>
|
||||
|
||||
|
||||
Link with B<-lapparmor> when compiling.
|
||||
|
|
|
@ -26,9 +26,9 @@ INCLUDES = $(all_includes)
|
|||
# For more information, see:
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 3
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 2
|
||||
AA_LIB_CURRENT = 4
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 3
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
|
|
|
@ -166,6 +166,11 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
|||
%token TOK_SYSLOG_KERNEL
|
||||
%token TOK_SYSLOG_USER
|
||||
|
||||
%destructor { free($$); } TOK_QUOTED_STRING TOK_ID TOK_MODE TOK_DMESG_STAMP
|
||||
%destructor { free($$); } TOK_AUDIT_DIGITS TOK_DATE_MONTH TOK_DATE TOK_TIME
|
||||
%destructor { free($$); } TOK_HEXSTRING TOK_TYPE_OTHER TOK_MSG_REST
|
||||
%destructor { free($$); } TOK_IP_ADDR
|
||||
|
||||
%%
|
||||
|
||||
log_message: audit_type
|
||||
|
@ -201,7 +206,7 @@ other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
|
|||
;
|
||||
|
||||
dmesg_type: TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($1); }
|
||||
;
|
||||
|
||||
syslog_type:
|
||||
|
|
|
@ -34,19 +34,25 @@ int main(void)
|
|||
retstr = hex_to_string("2F746D702F646F6573206E6F74206578697374");
|
||||
MY_TEST(retstr, "basic allocation");
|
||||
MY_TEST(strcmp(retstr, "/tmp/does not exist") == 0, "basic dehex 1");
|
||||
free(retstr);
|
||||
|
||||
retstr = hex_to_string("61");
|
||||
MY_TEST(strcmp(retstr, "a") == 0, "basic dehex 2");
|
||||
free(retstr);
|
||||
|
||||
retstr = hex_to_string("");
|
||||
MY_TEST(strcmp(retstr, "") == 0, "empty string");
|
||||
free(retstr);
|
||||
|
||||
/* ipproto_to_string() tests */
|
||||
retstr = ipproto_to_string((unsigned) 99999);
|
||||
MY_TEST(strcmp(retstr, "unknown(99999)") == 0, "invalid protocol test");
|
||||
free(retstr);
|
||||
|
||||
retstr = ipproto_to_string((unsigned) 6);
|
||||
MY_TEST(strcmp(retstr, "tcp") == 0, "protocol=tcp");
|
||||
free(retstr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,5 +15,10 @@ test_multi_multi_LDADD = -L../src/.libs -lapparmor
|
|||
|
||||
clean-local:
|
||||
rm -rf tmp.err.* tmp.out.* site.exp site.bak test_multi/out
|
||||
rm -f libaalogparse.log libaalogparse.sum
|
||||
|
||||
check-local:
|
||||
if ! test -f libaalogparse.log ; then echo '*** libaalogparse.log not found - is dejagnu installed? ***'; exit 1; fi
|
||||
if grep ERROR libaalogparse.log ; then exit 1 ; fi
|
||||
|
||||
EXTRA_DIST = test_multi/*.in test_multi/*.out test_multi/*.err
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
type=AVC msg=audit(1449442292.901:961): apparmor="ALLOWED" operation="change_hat" profile="/usr/sbin/httpd{,2}-prefork" pid=8527 comm="httpd-prefork" target="/usr/sbin/httpd{,2}-prefork//HANDLING_UNTRUSTED_INPUT"
|
|
@ -0,0 +1,11 @@
|
|||
START
|
||||
File: testcase_changehat_01.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1449442292.901:961
|
||||
Operation: change_hat
|
||||
Profile: /usr/sbin/httpd{,2}-prefork
|
||||
Command: httpd-prefork
|
||||
Name2: /usr/sbin/httpd{,2}-prefork//HANDLING_UNTRUSTED_INPUT
|
||||
PID: 8527
|
||||
Epoch: 1449442292
|
||||
Audit subid: 961
|
|
@ -0,0 +1 @@
|
|||
Jul 25 15:02:00 redacted kernel: [ 296.524447] audit: type=1400 audit(1437850920.403:64): apparmor="ALLOWED" operation="open" profile="/usr/sbin/vsftpd" name="/home/bane/foo" pid=1811 comm="vsftpd" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
|
|
@ -0,0 +1,15 @@
|
|||
START
|
||||
File: testcase_syslog_read.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1437850920.403:64
|
||||
Operation: open
|
||||
Mask: r
|
||||
Denied Mask: r
|
||||
fsuid: 1000
|
||||
ouid: 1000
|
||||
Profile: /usr/sbin/vsftpd
|
||||
Name: /home/bane/foo
|
||||
Command: vsftpd
|
||||
PID: 1811
|
||||
Epoch: 1437850920
|
||||
Audit subid: 64
|
|
@ -103,7 +103,7 @@ capabilities(7))
|
|||
|
||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||
|
||||
B<DOMAIN> = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' | 'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' ) ','
|
||||
B<DOMAIN> = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' | 'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'mpls' | 'ib' ) ','
|
||||
|
||||
B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
||||
|
||||
|
@ -161,7 +161,7 @@ B<SIGNAL SET> = 'set' '=' '(' I<SIGNAL LIST> ')'
|
|||
|
||||
B<SIGNAL LIST> = Comma or space separated list of I<SIGNALS>
|
||||
|
||||
B<SIGNALS> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' )
|
||||
B<SIGNALS> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32' )
|
||||
|
||||
B<SIGNAL PEER> = 'peer' '=' I<AARE>
|
||||
|
||||
|
@ -231,11 +231,13 @@ B<RLIMIT RULE> = 'set' 'rlimit' [I<RLIMIT> 'E<lt>=' I<RLIMIT VALUE> ]
|
|||
|
||||
B<RLIMIT> = ( 'cpu' | 'fsize' | 'data' | 'stack' | 'core' | 'rss' | 'nofile' | 'ofile' | 'as' | 'nproc' | 'memlock' | 'locks' | 'sigpending' | 'msgqueue' | 'nice' | 'rtprio' | 'rttime' )
|
||||
|
||||
B<RLIMIT VALUE> = ( I<RLIMIT SIZE> | I<RLIMIT NUMBER> | I<RLIMIT NICE> )
|
||||
B<RLIMIT VALUE> = ( I<RLIMIT SIZE> | I<RLIMIT NUMBER> | I<RLIMIT TIME> | I<RLIMIT NICE> )
|
||||
|
||||
B<RLIMIT SIZE> = I<NUMBER> ( 'K' | 'M' | 'G' ) Only applies to RLIMIT of 'fsize', 'data', 'stack', 'core', 'rss', 'as', 'memlock', 'msgqueue'.
|
||||
|
||||
B<RLIMIT NUMBER> = number from 0 to max rlimit value. Only applies ot RLIMIT of 'nofile', 'locks', 'sigpending', 'nproc', 'rtprio', 'cpu'
|
||||
B<RLIMIT NUMBER> = number from 0 to max rlimit value. Only applies ot RLIMIT of 'ofile', 'nofile', 'locks', 'sigpending', 'nproc', 'rtprio'
|
||||
|
||||
B<RLIMIT TIME> = I<NUMBER> ( 'us' | 'microsecond' | 'microseconds' | 'ms' | 'millisecond' | 'milliseconds' | 's' | 'sec' | 'second' | 'seconds' | 'min' | 'minute' | 'minutes' | 'h' | 'hour' | 'hours' | 'd' | 'day' | 'days' | 'week' | 'weeks' ) Only applies to RLIMIT of 'cpu', 'rttime'. RLIMIT 'cpu' only allows units >= 'seconds'.
|
||||
|
||||
B<RLIMIT NICE> = a number between -20 and 19. Only applies to RLIMIT of 'nice'
|
||||
|
||||
|
@ -962,6 +964,9 @@ Example AppArmor signal rules:
|
|||
# Allow us to signal ourselves using the built-in @{profile_name} variable
|
||||
signal peer=@{profile_name},
|
||||
|
||||
# Allow two real-time signals
|
||||
signal set=(rtmin+0 rtmin+32),
|
||||
|
||||
=head2 DBus rules
|
||||
|
||||
AppArmor supports DBus mediation. The mediation is performed in conjunction
|
||||
|
@ -1227,8 +1232,10 @@ provided AppArmor policy:
|
|||
@{HOMEDIRS}
|
||||
@{multiarch}
|
||||
@{pid}
|
||||
@{pids}
|
||||
@{PROC}
|
||||
@{securityfs}
|
||||
@{apparmorfs}
|
||||
@{sys}
|
||||
@{tid}
|
||||
@{XDG_DESKTOP_DIR}
|
||||
|
|
|
@ -278,9 +278,32 @@ the matching stats flag.
|
|||
|
||||
Use --help=dump to see a full list of which dump flags are supported
|
||||
|
||||
=item -j n, --jobs=n
|
||||
|
||||
Set the number of jobs used to compile the specified policy. Where n can
|
||||
be
|
||||
|
||||
# - a specific number of jobs
|
||||
auto - the # of cpus in the in the system
|
||||
x# - # * number of cpus
|
||||
|
||||
Eg.
|
||||
-j8 OR --jobs=8 allows for 8 parallel jobs
|
||||
-jauto OR --jobs=auto sets the jobs to the # of cpus
|
||||
-jx4 OR --jobs=x4 sets the jobs to # of cpus * 4
|
||||
-jx1 is equivalent to -jauto
|
||||
|
||||
The default value is the number of cpus in the system.
|
||||
|
||||
=item --max-jobs n
|
||||
|
||||
Set a hard cap on the value that can be specified by the --jobs flag.
|
||||
It takes the same set of options available to the --jobs option, and
|
||||
defaults to 8*cpus
|
||||
|
||||
=item -O n, --optimize=n
|
||||
|
||||
Set the optimization flags used by policy compilation. A sinlge optimization
|
||||
Set the optimization flags used by policy compilation. A single optimization
|
||||
flag can be toggled per -O option, but the optimize flag can be passed
|
||||
multiple times. Turning off some phases of the optimization can make
|
||||
it so that policy can't complete compilation due to size constraints
|
||||
|
|
|
@ -96,13 +96,13 @@ ostream &operator<<(ostream &os, Node &node);
|
|||
/* An abstract node in the syntax tree. */
|
||||
class Node {
|
||||
public:
|
||||
Node(): nullable(false) { child[0] = child[1] = 0; }
|
||||
Node(Node *left): nullable(false)
|
||||
Node(): nullable(false), label(0) { child[0] = child[1] = 0; }
|
||||
Node(Node *left): nullable(false), label(0)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = 0;
|
||||
}
|
||||
Node(Node *left, Node *right): nullable(false)
|
||||
Node(Node *left, Node *right): nullable(false), label(0)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = right;
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT))
|
||||
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT & ~MS_BIND & ~MS_RBIND))
|
||||
|
||||
#define MNT_SRC_OPT 1
|
||||
#define MNT_DST_OPT 2
|
||||
|
|
|
@ -402,6 +402,9 @@ extern void free_cod_entries(struct cod_entry *list);
|
|||
extern void __debug_capabilities(uint64_t capset, const char *name);
|
||||
void debug_cod_entries(struct cod_entry *list);
|
||||
|
||||
#define SECONDS_P_MS (1000LL * 1000LL)
|
||||
long long convert_time_units(long long value, long long base, const char *units);
|
||||
|
||||
|
||||
/* parser_symtab.c */
|
||||
struct set_value {
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
* numbers where supported.
|
||||
*/
|
||||
uint32_t policy_version = 2;
|
||||
uint32_t parser_abi_version = 1;
|
||||
uint32_t parser_abi_version = 2;
|
||||
uint32_t kernel_abi_version = 5;
|
||||
|
||||
int force_complain = 0;
|
||||
|
|
|
@ -447,7 +447,7 @@ LT_EQUAL <=
|
|||
}
|
||||
|
||||
<RLIMIT_MODE>{
|
||||
-?{NUMBER}[[:alpha:]]* {
|
||||
-?{NUMBER} {
|
||||
yylval.var_val = strdup(yytext);
|
||||
RETURN_TOKEN(TOK_VALUE);
|
||||
}
|
||||
|
@ -519,7 +519,14 @@ LT_EQUAL <=
|
|||
#include/.*\r?\n {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
*/
|
||||
yy_push_state(INCLUDE);
|
||||
}
|
||||
|
||||
include/{WS} {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
yy_push_state(INCLUDE);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,11 @@
|
|||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
|
||||
#include "lib.h"
|
||||
#include "features.h"
|
||||
#include "parser.h"
|
||||
|
@ -76,6 +79,18 @@ int abort_on_error = 0; /* stop processing profiles if error */
|
|||
int skip_bad_cache_rebuild = 0;
|
||||
int mru_skip_cache = 1;
|
||||
int debug_cache = 0;
|
||||
|
||||
/* for jobs_max and jobs
|
||||
* LONG_MAX : no limit
|
||||
* 0 : auto = detect system processing cores
|
||||
* n : use that number of processes/threads to compile policy
|
||||
*/
|
||||
#define JOBS_AUTO 0
|
||||
long jobs_max = -8; /* 8 * cpus */
|
||||
long jobs = JOBS_AUTO; /* default: number of processor cores */
|
||||
long njobs = 0;
|
||||
bool debug_jobs = false;
|
||||
|
||||
struct timespec cache_tstamp, mru_policy_tstamp;
|
||||
|
||||
static char *apparmorfs = NULL;
|
||||
|
@ -84,7 +99,7 @@ static char *cacheloc = NULL;
|
|||
static aa_features *features = NULL;
|
||||
|
||||
/* Make sure to update BOTH the short and long_options */
|
||||
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:";
|
||||
static const char *short_options = "ad::f:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:j:";
|
||||
struct option long_options[] = {
|
||||
{"add", 0, 0, 'a'},
|
||||
{"binary", 0, 0, 'B'},
|
||||
|
@ -116,7 +131,7 @@ struct option long_options[] = {
|
|||
{"purge-cache", 0, 0, 130}, /* no short option */
|
||||
{"create-cache-dir", 0, 0, 131}, /* no short option */
|
||||
{"cache-loc", 1, 0, 'L'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"debug", 2, 0, 'd'},
|
||||
{"dump", 1, 0, 'D'},
|
||||
{"Dump", 1, 0, 'D'},
|
||||
{"optimize", 1, 0, 'O'},
|
||||
|
@ -126,6 +141,8 @@ struct option long_options[] = {
|
|||
{"skip-bad-cache-rebuild", 0, 0, 133}, /* no short option */
|
||||
{"warn", 1, 0, 134}, /* no short option */
|
||||
{"debug-cache", 0, 0, 135}, /* no short option */
|
||||
{"jobs", 1, 0, 'j'},
|
||||
{"max-jobs", 1, 0, 136}, /* no short option */
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
|
@ -170,11 +187,13 @@ static void display_usage(const char *command)
|
|||
"-v, --verbose Show profile names as they load\n"
|
||||
"-Q, --skip-kernel-load Do everything except loading into kernel\n"
|
||||
"-V, --version Display version info and exit\n"
|
||||
"-d, --debug Debug apparmor definitions\n"
|
||||
"-d [n], --debug Debug apparmor definitions OR [n]\n"
|
||||
"-p, --preprocess Dump preprocessed profile\n"
|
||||
"-D [n], --dump Dump internal info for debugging\n"
|
||||
"-O [n], --Optimize Control dfa optimizations\n"
|
||||
"-h [cmd], --help[=cmd] Display this text or info about cmd\n"
|
||||
"-j n, --jobs n Set the number of compile threads\n"
|
||||
"--max-jobs n Hard cap on --jobs. Default 8*cpus\n"
|
||||
"--abort-on-error Abort processing of profiles on first error\n"
|
||||
"--skip-bad-cache-rebuild Do not try rebuilding the cache if it is rejected by the kernel\n"
|
||||
"--warn n Enable warnings (see --help=warn)\n"
|
||||
|
@ -268,6 +287,32 @@ static int getopt_long_file(FILE *f, const struct option *longopts,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long process_jobs_arg(const char *arg, const char *val) {
|
||||
char *end;
|
||||
long n;
|
||||
|
||||
if (!val || strcmp(val, "auto") == 0)
|
||||
n = JOBS_AUTO;
|
||||
else if (strcmp(val, "max") == 0)
|
||||
n = LONG_MAX;
|
||||
else {
|
||||
bool multiple = false;
|
||||
if (*val == 'x') {
|
||||
multiple = true;
|
||||
val++;
|
||||
}
|
||||
n = strtol(val, &end, 0);
|
||||
if (!(*val && val != end && *end == '\0')) {
|
||||
PERROR("%s: Invalid option %s=%s%s\n", progname, arg, multiple ? "x" : "", val);
|
||||
exit(1);
|
||||
}
|
||||
if (multiple)
|
||||
n = -n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* process a single argment from getopt_long
|
||||
* Returns: 1 if an action arg, else 0
|
||||
*/
|
||||
|
@ -286,8 +331,17 @@ static int process_arg(int c, char *optarg)
|
|||
option = OPTION_ADD;
|
||||
break;
|
||||
case 'd':
|
||||
debug++;
|
||||
skip_read_cache = 1;
|
||||
if (!optarg) {
|
||||
debug++;
|
||||
skip_read_cache = 1;
|
||||
} else if (strcmp(optarg, "jobs") == 0 ||
|
||||
strcmp(optarg, "j") == 0) {
|
||||
debug_jobs = true;
|
||||
} else {
|
||||
PERROR("%s: Invalid --debug option '%s'\n",
|
||||
progname, optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (!optarg) {
|
||||
|
@ -470,6 +524,12 @@ static int process_arg(int c, char *optarg)
|
|||
case 135:
|
||||
debug_cache = 1;
|
||||
break;
|
||||
case 'j':
|
||||
jobs = process_jobs_arg("-j", optarg);
|
||||
break;
|
||||
case 136:
|
||||
jobs_max = process_jobs_arg("max-jobs", optarg);
|
||||
break;
|
||||
default:
|
||||
display_usage(progname);
|
||||
exit(1);
|
||||
|
@ -803,6 +863,118 @@ out:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* Do not call directly, this is a helper for work_sync, which can handle
|
||||
* single worker cases and cases were the work queue is optimized away
|
||||
*
|
||||
* call only if there are work children to wait on
|
||||
*/
|
||||
#define work_sync_one(RESULT) \
|
||||
do { \
|
||||
int status; \
|
||||
wait(&status); \
|
||||
if (WIFEXITED(status)) \
|
||||
RESULT(WEXITSTATUS(status)); \
|
||||
else \
|
||||
RESULT(ECHILD); \
|
||||
/* TODO: do we need to handle traced */ \
|
||||
njobs--; \
|
||||
if (debug_jobs) \
|
||||
fprintf(stderr, " JOBS SYNC ONE: result %d, jobs left %ld\n", status, njobs); \
|
||||
} while (0)
|
||||
|
||||
#define work_sync(RESULT) \
|
||||
do { \
|
||||
if (debug_jobs) \
|
||||
fprintf(stderr, "JOBS SYNC: jobs left %ld\n", njobs); \
|
||||
while (njobs) \
|
||||
work_sync_one(RESULT); \
|
||||
} while (0)
|
||||
|
||||
#define work_spawn(WORK, RESULT) \
|
||||
do { \
|
||||
/* what to do to avoid fork() overhead when single threaded \
|
||||
if (jobs == 1) { \
|
||||
// no parallel work so avoid fork() overhead \
|
||||
RESULT(WORK); \
|
||||
break; \
|
||||
}*/ \
|
||||
if (njobs == jobs) { \
|
||||
/* wait for a child */ \
|
||||
if (debug_jobs) \
|
||||
fprintf(stderr, " JOBS SPAWN: waiting (jobs %ld == max %ld) ...\n", njobs, jobs); \
|
||||
work_sync_one(RESULT); \
|
||||
} \
|
||||
\
|
||||
pid_t child = fork(); \
|
||||
if (child == 0) { \
|
||||
/* child - exit work unit with returned value */ \
|
||||
exit(WORK); \
|
||||
} else if (child > 0) { \
|
||||
/* parent */ \
|
||||
njobs++; \
|
||||
if (debug_jobs) \
|
||||
fprintf(stderr, " JOBS SPAWN: created %ld ...\n", njobs); \
|
||||
} else { \
|
||||
/* error */ \
|
||||
if (debug_jobs) \
|
||||
fprintf(stderr, " JOBS SPAWN: failed error: %d) ...\n", errno); \
|
||||
RESULT(errno); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* sadly C forces us to do this with exit, long_jump or returning error
|
||||
* from work_spawn and work_sync. We could throw a C++ exception, is it
|
||||
* worth doing it to avoid the exit here.
|
||||
*
|
||||
* atm not all resources maybe cleanedup at exit
|
||||
*/
|
||||
int last_error = 0;
|
||||
void handle_work_result(int retval)
|
||||
{
|
||||
if (retval) {
|
||||
last_error = retval;
|
||||
if (abort_on_error) {
|
||||
/* already in abort mode we don't need subsequent
|
||||
* syncs to do this too
|
||||
*/
|
||||
abort_on_error = 0;
|
||||
work_sync(handle_work_result);
|
||||
exit(last_error);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static long compute_jobs(long n, long j)
|
||||
{
|
||||
if (j == JOBS_AUTO)
|
||||
j = n;
|
||||
else if (j < 0)
|
||||
j = n * j * -1;
|
||||
return j;
|
||||
}
|
||||
|
||||
static void setup_parallel_compile(void)
|
||||
{
|
||||
/* jobs and paralell_max set by default, config or args */
|
||||
long n = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (n == -1)
|
||||
/* unable to determine number of processors, default to 1 */
|
||||
n = 1;
|
||||
jobs = compute_jobs(n, jobs);
|
||||
jobs_max = compute_jobs(n, jobs_max);
|
||||
|
||||
if (jobs > jobs_max) {
|
||||
pwarn("%s: Warning capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
progname, jobs_max, jobs);
|
||||
jobs = jobs_max;
|
||||
}
|
||||
njobs = 0;
|
||||
if (debug_jobs)
|
||||
fprintf(stderr, "jobs: %ld\n", jobs);
|
||||
}
|
||||
|
||||
struct dir_cb_data {
|
||||
aa_kernel_interface *kernel_interface;
|
||||
const char *dirname; /* name of the parent dir */
|
||||
|
@ -820,8 +992,9 @@ static int profile_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
|||
autofree char *path = NULL;
|
||||
if (asprintf(&path, "%s/%s", cb_data->dirname, name) < 0)
|
||||
PERROR(_("Out of memory"));
|
||||
rc = process_profile(option, cb_data->kernel_interface, path,
|
||||
cb_data->cachedir);
|
||||
work_spawn(process_profile(option, cb_data->kernel_interface,
|
||||
path, cb_data->cachedir),
|
||||
handle_work_result);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -837,7 +1010,9 @@ static int binary_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
|||
autofree char *path = NULL;
|
||||
if (asprintf(&path, "%s/%s", cb_data->dirname, name) < 0)
|
||||
PERROR(_("Out of memory"));
|
||||
rc = process_binary(option, cb_data->kernel_interface, path);
|
||||
work_spawn(process_binary(option, cb_data->kernel_interface,
|
||||
path),
|
||||
handle_work_result);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -860,8 +1035,8 @@ static void setup_flags(void)
|
|||
int main(int argc, char *argv[])
|
||||
{
|
||||
aa_kernel_interface *kernel_interface = NULL;
|
||||
aa_policy_cache *policy_cache;
|
||||
int retval, last_error;
|
||||
aa_policy_cache *policy_cache = NULL;
|
||||
int retval;
|
||||
int i;
|
||||
int optind;
|
||||
|
||||
|
@ -873,6 +1048,8 @@ int main(int argc, char *argv[])
|
|||
process_config_file("/etc/apparmor/parser.conf");
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
setup_parallel_compile();
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
@ -964,8 +1141,10 @@ int main(int argc, char *argv[])
|
|||
void *data);
|
||||
struct dir_cb_data cb_data;
|
||||
|
||||
memset(&cb_data, 0, sizeof(struct dir_cb_data));
|
||||
cb_data.dirname = profilename;
|
||||
cb_data.cachedir = cacheloc;
|
||||
cb_data.kernel_interface = kernel_interface;
|
||||
cb = binary_input ? binary_dir_cb : profile_dir_cb;
|
||||
if ((retval = dirat_for_each(AT_FDCWD, profilename,
|
||||
&cb_data, cb))) {
|
||||
|
@ -973,25 +1152,23 @@ int main(int argc, char *argv[])
|
|||
profilename);
|
||||
}
|
||||
} else if (binary_input) {
|
||||
retval = process_binary(option, kernel_interface,
|
||||
profilename);
|
||||
work_spawn(process_binary(option, kernel_interface,
|
||||
profilename),
|
||||
handle_work_result);
|
||||
} else {
|
||||
retval = process_profile(option, kernel_interface,
|
||||
profilename, cacheloc);
|
||||
work_spawn(process_profile(option, kernel_interface,
|
||||
profilename, cacheloc),
|
||||
handle_work_result);
|
||||
}
|
||||
|
||||
if (profilename) free(profilename);
|
||||
profilename = NULL;
|
||||
|
||||
if (retval) {
|
||||
last_error = retval;
|
||||
if (abort_on_error)
|
||||
break;
|
||||
}
|
||||
}
|
||||
work_sync(handle_work_result);
|
||||
|
||||
if (ofile)
|
||||
fclose(ofile);
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
|
|
@ -724,7 +724,7 @@ static const char *capnames[] = {
|
|||
"audit_write",
|
||||
"audit_control",
|
||||
"setfcap",
|
||||
"mac_override"
|
||||
"mac_override",
|
||||
"syslog",
|
||||
};
|
||||
|
||||
|
@ -867,6 +867,54 @@ void print_cond_entry(struct cond_entry *ent)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct time_units {
|
||||
const char *str;
|
||||
long long value;
|
||||
};
|
||||
|
||||
static struct time_units time_units[] = {
|
||||
{ "us", 1LL },
|
||||
{ "microsecond", 1LL },
|
||||
{ "microseconds", 1LL },
|
||||
{ "ms", 1000LL },
|
||||
{ "millisecond", 1000LL },
|
||||
{ "milliseconds", 1000LL },
|
||||
{ "s", 1000LL * 1000LL },
|
||||
{ "sec", SECONDS_P_MS },
|
||||
{ "second", SECONDS_P_MS },
|
||||
{ "seconds", SECONDS_P_MS },
|
||||
{ "min" , 60LL * SECONDS_P_MS },
|
||||
{ "minute", 60LL * SECONDS_P_MS },
|
||||
{ "minutes", 60LL * SECONDS_P_MS },
|
||||
{ "h", 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "hour", 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "hours", 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "d", 24LL * 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "day", 24LL * 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "days", 24LL * 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "week", 7LL * 24LL * 60LL * 60LL * SECONDS_P_MS },
|
||||
{ "weeks", 7LL * 24LL * 60LL * 60LL * SECONDS_P_MS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
long long convert_time_units(long long value, long long base, const char *units)
|
||||
{
|
||||
struct time_units *ent;
|
||||
if (!units)
|
||||
/* default to base if no units */
|
||||
return value;
|
||||
|
||||
for (ent = time_units; ent->str; ent++) {
|
||||
if (strcmp(ent->str, units) == 0) {
|
||||
if (value * ent->value < base)
|
||||
return -1LL;
|
||||
return value * ent->value / base;
|
||||
}
|
||||
}
|
||||
return -2LL;
|
||||
}
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
#include "unit_test.h"
|
||||
|
@ -1085,6 +1133,50 @@ int test_processquoted(void)
|
|||
return rc;
|
||||
}
|
||||
|
||||
#define TIME_TEST(V, B, U, R) \
|
||||
MY_TEST(convert_time_units((V), (B), U) == (R), \
|
||||
"convert " #V " with base of " #B ", " #U " units")
|
||||
|
||||
int test_convert_time_units()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
TIME_TEST(1LL, 1LL, NULL, 1LL);
|
||||
TIME_TEST(12345LL, 1LL, NULL, 12345LL);
|
||||
TIME_TEST(10LL, 10LL, NULL, 10LL);
|
||||
TIME_TEST(123450LL, 10LL, NULL, 123450LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "us", 12345LL);
|
||||
TIME_TEST(12345LL, 1LL, "microsecond", 12345LL);
|
||||
TIME_TEST(12345LL, 1LL, "microseconds", 12345LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "ms", 12345LL*1000LL);
|
||||
TIME_TEST(12345LL, 1LL, "millisecond", 12345LL*1000LL);
|
||||
TIME_TEST(12345LL, 1LL, "milliseconds", 12345LL*1000LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "s", 12345LL*1000LL*1000LL);
|
||||
TIME_TEST(12345LL, 1LL, "sec", 12345LL*1000LL*1000LL);
|
||||
TIME_TEST(12345LL, 1LL, "second", 12345LL*1000LL*1000LL);
|
||||
TIME_TEST(12345LL, 1LL, "seconds", 12345LL*1000LL*1000LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "min", 12345LL*1000LL*1000LL*60LL);
|
||||
TIME_TEST(12345LL, 1LL, "minute", 12345LL*1000LL*1000LL*60LL);
|
||||
TIME_TEST(12345LL, 1LL, "minutes", 12345LL*1000LL*1000LL*60LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "h", 12345LL*1000LL*1000LL*60LL*60LL);
|
||||
TIME_TEST(12345LL, 1LL, "hour", 12345LL*1000LL*1000LL*60LL*60LL);
|
||||
TIME_TEST(12345LL, 1LL, "hours", 12345LL*1000LL*1000LL*60LL*60LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "d", 12345LL*1000LL*1000LL*60LL*60LL*24LL);
|
||||
TIME_TEST(12345LL, 1LL, "day", 12345LL*1000LL*1000LL*60LL*60LL*24LL);
|
||||
TIME_TEST(12345LL, 1LL, "days", 12345LL*1000LL*1000LL*60LL*60LL*24LL);
|
||||
|
||||
TIME_TEST(12345LL, 1LL, "week", 12345LL*1000LL*1000LL*60LL*60LL*24LL*7LL);
|
||||
TIME_TEST(12345LL, 1LL, "weeks", 12345LL*1000LL*1000LL*60LL*60LL*24LL*7LL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -1102,6 +1194,10 @@ int main(void)
|
|||
if (retval != 0)
|
||||
rc = retval;
|
||||
|
||||
retval = test_convert_time_units();
|
||||
if (retval != 0)
|
||||
rc = retval;
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif /* UNIT_TEST */
|
||||
|
|
|
@ -275,12 +275,51 @@ static int process_variables_in_rules(Profile &prof)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int process_variables_in_name(Profile &prof)
|
||||
{
|
||||
/* this needs to be done before alias expansion, ie. altnames are
|
||||
* setup
|
||||
*/
|
||||
int error = expand_entry_variables(&prof.name);
|
||||
if (!error && prof.attachment)
|
||||
error = expand_entry_variables(&prof.attachment);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static std::string escape_re(std::string str)
|
||||
{
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
if (str[i] == '\\') {
|
||||
/* skip \ and follow char. Skipping \ and first
|
||||
* char is enough for multichar escape sequence
|
||||
*/
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (strchr("{}[]*?", str[i]) != NULL) {
|
||||
str.insert(i++, "\\");
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int process_profile_variables(Profile *prof)
|
||||
{
|
||||
int error = 0, rc;
|
||||
|
||||
error = new_set_var(PROFILE_NAME_VARIABLE, prof->get_name(true).c_str());
|
||||
/* needs to be before PROFILE_NAME_VARIABLE so that variable will
|
||||
* have the correct name
|
||||
*/
|
||||
error = process_variables_in_name(*prof);
|
||||
|
||||
if (!error) {
|
||||
/* escape profile name elements that could be interpreted
|
||||
* as regular expressions.
|
||||
*/
|
||||
error = new_set_var(PROFILE_NAME_VARIABLE, escape_re(prof->get_name(false)).c_str());
|
||||
}
|
||||
|
||||
if (!error)
|
||||
error = process_variables_in_entries(prof->entries);
|
||||
|
|
|
@ -78,7 +78,6 @@ mnt_rule *do_mnt_rule(struct cond_entry *src_conds, char *src,
|
|||
int mode);
|
||||
mnt_rule *do_pivot_rule(struct cond_entry *old, char *root,
|
||||
char *transition);
|
||||
|
||||
void add_local_entry(Profile *prof);
|
||||
|
||||
%}
|
||||
|
@ -252,6 +251,7 @@ void add_local_entry(Profile *prof);
|
|||
%type <val_list> valuelist
|
||||
%type <boolean> expr
|
||||
%type <id> id_or_var
|
||||
%type <id> opt_id_or_var
|
||||
%type <boolean> opt_subset_flag
|
||||
%type <boolean> opt_audit_flag
|
||||
%type <boolean> opt_owner_flag
|
||||
|
@ -307,7 +307,10 @@ opt_ns: { /* nothing */ $$ = NULL; }
|
|||
opt_id: { /* nothing */ $$ = NULL; }
|
||||
| TOK_ID { $$ = $1; }
|
||||
|
||||
profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
||||
opt_id_or_var: { /* nothing */ $$ = NULL; }
|
||||
| id_or_var { $$ = $1; }
|
||||
|
||||
profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
Profile *prof = $5;
|
||||
|
||||
|
@ -315,13 +318,17 @@ profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
|
|||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
/* Honor the --namespace-string command line option */
|
||||
if (profile_ns) {
|
||||
prof->ns = strdup(profile_ns);
|
||||
if (!prof->ns)
|
||||
yyerror(_("Memory allocation error."));
|
||||
}
|
||||
|
||||
prof->name = $1;
|
||||
prof->attachment = $2;
|
||||
if ($2 && $2[0] != '/')
|
||||
/* we don't support variables as part of the profile
|
||||
* name or attachment atm
|
||||
*/
|
||||
yyerror(_("Profile attachment must begin with a '/'."));
|
||||
if ($2 && !($2[0] == '/' || strncmp($2, "@{", 2) == 0))
|
||||
yyerror(_("Profile attachment must begin with a '/' or variable."));
|
||||
prof->flags = $3;
|
||||
if (force_complain && kernel_abi_version == 5)
|
||||
/* newer abis encode force complain as part of the
|
||||
|
@ -351,12 +358,17 @@ profile: opt_profile_flag opt_ns profile_base
|
|||
if ($3->name[0] != '/' && !($1 || $2))
|
||||
yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
|
||||
|
||||
if ($2 && profile_ns) {
|
||||
pwarn("%s: -n %s overriding policy specified namespace :%s:\n", progname, profile_ns, $2);
|
||||
if (prof->ns) {
|
||||
/**
|
||||
* Print warning if the profile specified a namespace
|
||||
* different than the one specified with the
|
||||
* --namespace-string command line option
|
||||
*/
|
||||
if ($2 && strcmp(prof->ns, $2)) {
|
||||
pwarn("%s: -n %s overriding policy specified namespace :%s:\n",
|
||||
progname, prof->ns, $2);
|
||||
}
|
||||
free($2);
|
||||
prof->ns = strdup(profile_ns);
|
||||
if (!prof->ns)
|
||||
yyerror(_("Memory allocation error."));
|
||||
} else
|
||||
prof->ns = $2;
|
||||
if ($1 == 2)
|
||||
|
@ -853,7 +865,7 @@ rules: rules cond_rule
|
|||
$$ = merge_policy($1, $2);
|
||||
}
|
||||
|
||||
rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
||||
rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
|
||||
{
|
||||
rlim_t value = RLIM_INFINITY;
|
||||
long long tmp;
|
||||
|
@ -866,11 +878,6 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
|||
if (strcmp($6, "infinity") == 0) {
|
||||
value = RLIM_INFINITY;
|
||||
} else {
|
||||
const char *seconds = "seconds";
|
||||
const char *milliseconds = "ms";
|
||||
const char *minutes = "minutes";
|
||||
const char *hours = "hours";
|
||||
const char *days = "days";
|
||||
const char *kb = "KB";
|
||||
const char *mb = "MB";
|
||||
const char *gb = "GB";
|
||||
|
@ -880,34 +887,25 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
|||
case RLIMIT_CPU:
|
||||
if (!end || $6 == end || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (*end == '\0' ||
|
||||
strstr(seconds, end) == seconds) {
|
||||
value = tmp;
|
||||
} else if (strstr(minutes, end) == minutes) {
|
||||
value = tmp * 60;
|
||||
} else if (strstr(hours, end) == hours) {
|
||||
value = tmp * 60 * 60;
|
||||
} else if (strstr(days, end) == days) {
|
||||
value = tmp * 60 * 60 * 24;
|
||||
} else {
|
||||
tmp = convert_time_units(tmp, SECONDS_P_MS, $7);
|
||||
if (tmp == -1LL)
|
||||
yyerror("RLIMIT '%s %s' < minimum value of 1s\n", $4, $6);
|
||||
else if (tmp < 0LL)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
}
|
||||
if (!$7)
|
||||
pwarn(_("RLIMIT 'cpu' no units specified using default units of seconds\n"));
|
||||
value = tmp;
|
||||
break;
|
||||
case RLIMIT_RTTIME:
|
||||
/* RTTIME is measured in microseconds */
|
||||
if (!end || $6 == end || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (*end == '\0') {
|
||||
value = tmp;
|
||||
} else if (strstr(milliseconds, end) == milliseconds) {
|
||||
value = tmp * 1000;
|
||||
} else if (strstr(seconds, end) == seconds) {
|
||||
value = tmp * 1000 * 1000;
|
||||
} else if (strstr(minutes, end) == minutes) {
|
||||
value = tmp * 1000 * 1000 * 60;
|
||||
} else {
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
}
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7 ? $7 : "");
|
||||
tmp = convert_time_units(tmp, 1LL, $7);
|
||||
if (tmp < 0LL)
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7 ? $7 : "");
|
||||
if (!$7)
|
||||
pwarn(_("RLIMIT 'rttime' no units specified using default units of microseconds\n"));
|
||||
value = tmp;
|
||||
break;
|
||||
case RLIMIT_NOFILE:
|
||||
case RLIMIT_NPROC:
|
||||
|
@ -915,15 +913,15 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
|||
case RLIMIT_SIGPENDING:
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
case RLIMIT_RTPRIO:
|
||||
if (!end || $6 == end || *end != '\0' || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (!end || $6 == end || $7 || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7 ? $7 : "");
|
||||
value = tmp;
|
||||
break;
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
case RLIMIT_NICE:
|
||||
if (!end || $6 == end || *end != '\0')
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (!end || $6 == end || $7)
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7 ? $7 : "");
|
||||
if (tmp < -20 || tmp > 19)
|
||||
yyerror("RLIMIT '%s' out of range (-20 .. 19) %d\n", $4, tmp);
|
||||
value = tmp + 20;
|
||||
|
@ -938,15 +936,17 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
|||
case RLIMIT_MEMLOCK:
|
||||
case RLIMIT_MSGQUEUE:
|
||||
if ($6 == end || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (strstr(kb, end) == kb) {
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7 ? $7 : "");
|
||||
if (!$7) {
|
||||
; /* use default of bytes */
|
||||
} else if (strstr(kb, $7) == kb) {
|
||||
tmp *= 1024;
|
||||
} else if (strstr(mb, end) == mb) {
|
||||
} else if (strstr(mb, $7) == mb) {
|
||||
tmp *= 1024*1024;
|
||||
} else if (strstr(gb, end) == gb) {
|
||||
} else if (strstr(gb, $7) == gb) {
|
||||
tmp *= 1024*1024*1024;
|
||||
} else if (*end != '\0') {
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
} else {
|
||||
yyerror("RLIMIT '%s' invalid value %s %s\n", $4, $6, $7);
|
||||
}
|
||||
value = tmp;
|
||||
break;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -25,8 +26,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
|
@ -166,12 +165,21 @@ void install_cache(const char *cachetmpname, const char *cachename)
|
|||
/* Only install the generate cache file if it parsed correctly
|
||||
and did not have write/close errors */
|
||||
if (cachetmpname) {
|
||||
struct timeval t;
|
||||
struct timespec times[2];
|
||||
|
||||
/* set the mtime of the cache file to the most newest mtime
|
||||
* of policy files used to generate it
|
||||
*/
|
||||
TIMESPEC_TO_TIMEVAL(&t, &mru_policy_tstamp);
|
||||
utimes(cachetmpname, &t);
|
||||
times[0].tv_sec = 0;
|
||||
times[0].tv_nsec = UTIME_OMIT;
|
||||
times[1] = mru_policy_tstamp;
|
||||
if (utimensat(AT_FDCWD, cachetmpname, times, 0) < 0) {
|
||||
PERROR("%s: Failed to set the mtime of cache file '%s': %m\n",
|
||||
progname, cachename);
|
||||
unlink(cachetmpname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rename(cachetmpname, cachename) < 0) {
|
||||
pwarn("Warning failed to write cache: %s\n", cachename);
|
||||
unlink(cachetmpname);
|
||||
|
|
|
@ -94,12 +94,13 @@ aa_log_skipped_msg() {
|
|||
echo -e "$rc_skipped"
|
||||
}
|
||||
|
||||
_set_status() {
|
||||
return $1
|
||||
}
|
||||
|
||||
aa_log_end_msg() {
|
||||
v="-v"
|
||||
if [ "$1" != '0' ]; then
|
||||
rc="-v$1"
|
||||
fi
|
||||
rc_status $v
|
||||
_set_status $1
|
||||
rc_status -v
|
||||
}
|
||||
|
||||
usage() {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Canonical Ltd.
|
||||
# Author: Steve Beattie <steve@nxnw.org>
|
||||
# Copyright (C) 2013-2015 Canonical Ltd.
|
||||
# Authors: Steve Beattie <steve@nxnw.org>
|
||||
# Tyler Hicks <tyhicks@canonical.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
|
@ -12,11 +13,11 @@
|
|||
|
||||
# TODO
|
||||
# - check cache not used if parser in $PATH is newer
|
||||
# - check cache used/not used if includes are newer/older
|
||||
# - check cache used for force-complain, disable symlink, etc.
|
||||
|
||||
from argparse import ArgumentParser
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import time
|
||||
import tempfile
|
||||
|
@ -24,19 +25,24 @@ import unittest
|
|||
|
||||
import testlib
|
||||
|
||||
ABSTRACTION_CONTENTS = '''
|
||||
# Simple example abstraction
|
||||
capability setuid,
|
||||
'''
|
||||
ABSTRACTION = 'suid-abstraction'
|
||||
|
||||
PROFILE_CONTENTS = '''
|
||||
# Simple example profile for caching tests
|
||||
|
||||
/bin/pingy {
|
||||
#include <%s>
|
||||
capability net_raw,
|
||||
capability setuid,
|
||||
network inet raw,
|
||||
|
||||
/bin/ping mixr,
|
||||
/etc/modules.conf r,
|
||||
}
|
||||
'''
|
||||
''' % (ABSTRACTION)
|
||||
PROFILE = 'sbin.pingy'
|
||||
config = None
|
||||
|
||||
|
@ -51,11 +57,6 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
|||
# REPORT ALL THE OUTPUT
|
||||
self.maxDiff = None
|
||||
|
||||
# skip all the things if apparmor securityfs isn't mounted
|
||||
if not os.path.exists("/sys/kernel/security/apparmor"):
|
||||
raise unittest.SkipTest("WARNING: /sys/kernel/security/apparmor does not exist. "
|
||||
"Skipping tests")
|
||||
|
||||
self.tmp_dir = tempfile.mkdtemp(prefix='aa-caching-')
|
||||
os.chmod(self.tmp_dir, 0o755)
|
||||
|
||||
|
@ -63,7 +64,11 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
|||
self.cache_dir = os.path.join(self.tmp_dir, 'cache')
|
||||
os.mkdir(self.cache_dir)
|
||||
|
||||
# write our sample profile out
|
||||
# default path of the output cache file
|
||||
self.cache_file = os.path.join(self.cache_dir, PROFILE)
|
||||
|
||||
# write our sample abstraction and profile out
|
||||
self.abstraction = testlib.write_file(self.tmp_dir, ABSTRACTION, ABSTRACTION_CONTENTS)
|
||||
self.profile = testlib.write_file(self.tmp_dir, PROFILE, PROFILE_CONTENTS)
|
||||
|
||||
if config.debug:
|
||||
|
@ -72,6 +77,9 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
|||
|
||||
self.cmd_prefix = [config.parser, '--base', self.tmp_dir, '--skip-kernel-load']
|
||||
|
||||
if not self.is_apparmorfs_mounted():
|
||||
self.cmd_prefix += ['-M', './features_files/features.all']
|
||||
|
||||
def tearDown(self):
|
||||
'''teardown for each test'''
|
||||
|
||||
|
@ -89,7 +97,17 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
|||
self.assertFalse(os.path.exists(path),
|
||||
'test created file %s, when it was not expected to do so' % path)
|
||||
|
||||
def is_apparmorfs_mounted(self):
|
||||
return os.path.exists("/sys/kernel/security/apparmor")
|
||||
|
||||
def require_apparmorfs(self):
|
||||
# skip the test if apparmor securityfs isn't mounted
|
||||
if not self.is_apparmorfs_mounted():
|
||||
raise unittest.SkipTest("WARNING: /sys/kernel/security/apparmor does not exist. Skipping test.")
|
||||
|
||||
def compare_features_file(self, features_path, expected=True):
|
||||
# tests that need this function should call require_apparmorfs() early
|
||||
|
||||
# compare features contents
|
||||
expected_output = testlib.read_features_dir('/sys/kernel/security/apparmor/features')
|
||||
with open(features_path) as f:
|
||||
|
@ -143,6 +161,8 @@ class AAParserBasicCachingTests(AAParserCachingCommon):
|
|||
def test_features_match_when_caching(self):
|
||||
'''test features file is written when caching'''
|
||||
|
||||
self.require_apparmorfs()
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
|
@ -203,21 +223,34 @@ class AAParserCachingTests(AAParserCachingCommon):
|
|||
def setUp(self):
|
||||
super(AAParserCachingTests, self).setUp()
|
||||
|
||||
# need separation of length timeout between generating profile
|
||||
# and generating cache entry, as the parser distinguishes
|
||||
# between ctime, not mtime.
|
||||
if not 'timeout' in dir(config):
|
||||
r = testlib.filesystem_time_resolution()
|
||||
config.timeout = r[1]
|
||||
|
||||
time.sleep(config.timeout)
|
||||
r = testlib.filesystem_time_resolution()
|
||||
self.mtime_res = r[1]
|
||||
|
||||
def _generate_cache_file(self):
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
|
||||
self.assert_path_exists(self.cache_file)
|
||||
|
||||
def _assertTimeStampEquals(self, time1, time2):
|
||||
'''Compare two timestamps to ensure equality'''
|
||||
|
||||
# python 3.2 and earlier don't support writing timestamps with
|
||||
# nanosecond resolution, only microsecond. When comparing
|
||||
# timestamps in such an environment, loosen the equality bounds
|
||||
# to compensate
|
||||
# Reference: https://bugs.python.org/issue12904
|
||||
(major, minor, _) = platform.python_version_tuple()
|
||||
if (int(major) < 3) or ((int(major) == 3) and (int(minor) <= 2)):
|
||||
self.assertAlmostEquals(time1, time2, places=5)
|
||||
else:
|
||||
self.assertEquals(time1, time2)
|
||||
|
||||
def _set_mtime(self, path, mtime):
|
||||
atime = os.stat(path).st_atime
|
||||
os.utime(path, (atime, mtime))
|
||||
self._assertTimeStampEquals(os.stat(path).st_mtime, mtime)
|
||||
|
||||
def test_cache_loaded_when_exists(self):
|
||||
'''test cache is loaded when it exists, is newer than profile, and features match'''
|
||||
|
@ -260,6 +293,8 @@ class AAParserCachingTests(AAParserCachingCommon):
|
|||
def test_cache_writing_does_not_overwrite_features_when_features_differ(self):
|
||||
'''test cache writing does not overwrite the features files when it differs and --skip-bad-cache is given'''
|
||||
|
||||
self.require_apparmorfs()
|
||||
|
||||
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
|
@ -277,11 +312,13 @@ class AAParserCachingTests(AAParserCachingCommon):
|
|||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '--write-cache', '--skip-bad-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE), expected=False)
|
||||
self.assert_path_exists(self.cache_file, expected=False)
|
||||
|
||||
def test_cache_writing_updates_features(self):
|
||||
'''test cache writing updates features'''
|
||||
|
||||
self.require_apparmorfs()
|
||||
|
||||
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
|
@ -294,18 +331,18 @@ class AAParserCachingTests(AAParserCachingCommon):
|
|||
'''test cache writing updates cache file'''
|
||||
|
||||
cache_file = testlib.write_file(self.cache_dir, PROFILE, 'monkey\n')
|
||||
orig_size = os.stat(cache_file).st_size
|
||||
orig_stat = os.stat(cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(cache_file)
|
||||
with open(cache_file, 'rb') as f:
|
||||
new_size = os.fstat(f.fileno()).st_size
|
||||
stat = os.stat(cache_file)
|
||||
# We check sizes here rather than whether the string monkey is
|
||||
# in cache_contents because of the difficulty coercing cache
|
||||
# file bytes into strings in python3
|
||||
self.assertNotEquals(orig_size, new_size, 'Expected cache file to be updated, size is not changed.')
|
||||
self.assertNotEquals(orig_stat.st_size, stat.st_size, 'Expected cache file to be updated, size is not changed.')
|
||||
self.assertEquals(os.stat(self.profile).st_mtime, stat.st_mtime)
|
||||
|
||||
def test_cache_writing_clears_all_files(self):
|
||||
'''test cache writing clears all cache files'''
|
||||
|
@ -317,27 +354,110 @@ class AAParserCachingTests(AAParserCachingCommon):
|
|||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(check_file, expected=False)
|
||||
|
||||
def test_profile_mtime_preserved(self):
|
||||
'''test profile mtime is preserved when it is newest'''
|
||||
expected = 1
|
||||
self._set_mtime(self.abstraction, 0)
|
||||
self._set_mtime(self.profile, expected)
|
||||
self._generate_cache_file()
|
||||
self.assertEquals(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_abstraction_mtime_preserved(self):
|
||||
'''test abstraction mtime is preserved when it is newest'''
|
||||
expected = 1000
|
||||
self._set_mtime(self.profile, 0)
|
||||
self._set_mtime(self.abstraction, expected)
|
||||
self._generate_cache_file()
|
||||
self.assertEquals(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_equal_mtimes_preserved(self):
|
||||
'''test equal profile and abstraction mtimes are preserved'''
|
||||
expected = 10000 + self.mtime_res
|
||||
self._set_mtime(self.profile, expected)
|
||||
self._set_mtime(self.abstraction, expected)
|
||||
self._generate_cache_file()
|
||||
self.assertEquals(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_profile_newer_skips_cache(self):
|
||||
'''test cache is skipped if profile is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
time.sleep(config.timeout)
|
||||
testlib.touch(self.profile)
|
||||
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
self._set_mtime(self.profile, profile_mtime)
|
||||
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertEquals(orig_stat.st_size, stat.st_size)
|
||||
self.assertEquals(orig_stat.st_ino, stat.st_ino)
|
||||
self.assertEquals(orig_stat.st_mtime, stat.st_mtime)
|
||||
|
||||
def test_abstraction_newer_skips_cache(self):
|
||||
'''test cache is skipped if abstraction is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
self._set_mtime(self.abstraction, abstraction_mtime)
|
||||
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertEquals(orig_stat.st_size, stat.st_size)
|
||||
self.assertEquals(orig_stat.st_ino, stat.st_ino)
|
||||
self.assertEquals(orig_stat.st_mtime, stat.st_mtime)
|
||||
|
||||
def test_profile_newer_rewrites_cache(self):
|
||||
'''test cache is rewritten if profile is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
self._set_mtime(self.profile, profile_mtime)
|
||||
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '-r', '-W', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertNotEquals(orig_stat.st_ino, stat.st_ino)
|
||||
self._assertTimeStampEquals(profile_mtime, stat.st_mtime)
|
||||
|
||||
def test_abstraction_newer_rewrites_cache(self):
|
||||
'''test cache is rewritten if abstraction is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
self._set_mtime(self.abstraction, abstraction_mtime)
|
||||
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(['-v', '-r', '-W', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertNotEquals(orig_stat.st_ino, stat.st_ino)
|
||||
self._assertTimeStampEquals(abstraction_mtime, stat.st_mtime)
|
||||
|
||||
def test_parser_newer_uses_cache(self):
|
||||
'''test cache is not skipped if parser is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
time.sleep(config.timeout)
|
||||
|
||||
# copy parser
|
||||
os.mkdir(os.path.join(self.tmp_dir, 'parser'))
|
||||
new_parser = os.path.join(self.tmp_dir, 'parser', 'apparmor_parser')
|
||||
shutil.copy(config.parser, new_parser)
|
||||
self._set_mtime(new_parser, os.stat(self.cache_file).st_mtime + self.mtime_res)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd[0] = new_parser
|
||||
|
@ -379,6 +499,7 @@ class AAParserAltCacheTests(AAParserCachingTests):
|
|||
|
||||
self.orig_cache_dir = self.cache_dir
|
||||
self.cache_dir = alt_cache_dir
|
||||
self.cache_file = os.path.join(self.cache_dir, PROFILE)
|
||||
self.cmd_prefix.extend(['--cache-loc', alt_cache_dir])
|
||||
|
||||
def tearDown(self):
|
||||
|
|
|
@ -464,6 +464,77 @@ verify_binary_equality "change_profile == change_profile -> **" \
|
|||
"/t { change_profile /**, }" \
|
||||
"/t { change_profile /** -> **, }"
|
||||
|
||||
verify_binary_equality "profile name is hname in rule" \
|
||||
":ns:/hname { signal peer=/hname, }" \
|
||||
":ns:/hname { signal peer=@{profile_name}, }"
|
||||
|
||||
verify_binary_inequality "profile name is NOT fq name in rule" \
|
||||
":ns:/hname { signal peer=:ns:/hname, }" \
|
||||
":ns:/hname { signal peer=@{profile_name}, }"
|
||||
|
||||
verify_binary_equality "profile name is hname in sub pofile rule" \
|
||||
":ns:/hname { profile child { signal peer=/hname//child, } }" \
|
||||
":ns:/hname { profile child { signal peer=@{profile_name}, } }"
|
||||
|
||||
verify_binary_inequality "profile name is NOT fq name in sub profile rule" \
|
||||
":ns:/hname { profile child { signal peer=:ns:/hname//child, } }" \
|
||||
":ns:/hname { profile child { signal peer=@{profile_name}, } }"
|
||||
|
||||
verify_binary_equality "profile name is hname in hat rule" \
|
||||
":ns:/hname { ^child { signal peer=/hname//child, } }" \
|
||||
":ns:/hname { ^child { signal peer=@{profile_name}, } }"
|
||||
|
||||
verify_binary_inequality "profile name is NOT fq name in hat rule" \
|
||||
":ns:/hname { ^child { signal peer=:ns:/hname//child, } }" \
|
||||
":ns:/hname { ^child { signal peer=@{profile_name}, } }"
|
||||
|
||||
verify_binary_equality "@{profile_name} is literal in peer" \
|
||||
"/{a,b} { signal peer=/\{a,b\}, }" \
|
||||
"/{a,b} { signal peer=@{profile_name}, }"
|
||||
|
||||
verify_binary_equality "@{profile_name} is literal in peer with pattern" \
|
||||
"/{a,b} { signal peer={/\{a,b\},c}, }" \
|
||||
"/{a,b} { signal peer={@{profile_name},c}, }"
|
||||
|
||||
verify_binary_inequality "@{profile_name} is not pattern in peer" \
|
||||
"/{a,b} { signal peer=/{a,b}, }" \
|
||||
"/{a,b} { signal peer=@{profile_name}, }"
|
||||
|
||||
verify_binary_equality "@{profile_name} is literal in peer with esc sequence" \
|
||||
"/\\\\a { signal peer=/\\\\a, }" \
|
||||
"/\\\\a { signal peer=@{profile_name}, }"
|
||||
|
||||
verify_binary_equality "@{profile_name} is literal in peer with esc alt sequence" \
|
||||
"/\\{a,b\\},c { signal peer=/\\{a,b\\},c, }" \
|
||||
"/\\{a,b\\},c { signal peer=@{profile_name}, }"
|
||||
|
||||
|
||||
|
||||
# verify rlimit data conversions
|
||||
verify_binary_equality "set rlimit rttime <= 12 weeks" \
|
||||
"/t { set rlimit rttime <= 12 weeks, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7)) days, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24)) hours, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60)) minutes, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60)) seconds, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000)) ms, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)) us, }" \
|
||||
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)), }"
|
||||
|
||||
verify_binary_equality "set rlimit cpu <= 42 weeks" \
|
||||
"/t { set rlimit cpu <= 42 weeks, }" \
|
||||
"/t { set rlimit cpu <= $((42 * 7)) days, }" \
|
||||
"/t { set rlimit cpu <= $((42 * 7 * 24)) hours, }" \
|
||||
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60)) minutes, }" \
|
||||
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)) seconds, }" \
|
||||
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)), }"
|
||||
|
||||
verify_binary_equality "set rlimit memlock <= 2GB" \
|
||||
"/t { set rlimit memlock <= 2GB, }" \
|
||||
"/t { set rlimit memlock <= $((2 * 1024)) MB, }" \
|
||||
"/t { set rlimit memlock <= $((2 * 1024 * 1024)) KB, }" \
|
||||
"/t { set rlimit memlock <= $((2 * 1024 * 1024 * 1024)) , }" \
|
||||
|
||||
if [ $fails -ne 0 -o $errors -ne 0 ]
|
||||
then
|
||||
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
|
||||
|
|
7
parser/tst/simple_tests/bare_include_tests/bad_1.sd
Normal file
7
parser/tst/simple_tests/bare_include_tests/bad_1.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - non-existent include should fail
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/does/not/exist {
|
||||
include <does-not-exist/does-not-exist>
|
||||
}
|
7
parser/tst/simple_tests/bare_include_tests/bad_2.sd
Normal file
7
parser/tst/simple_tests/bare_include_tests/bad_2.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - mis-parsing include should fail
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/does/not/exist {
|
||||
include does-not-exist/does-not-exist
|
||||
}
|
8
parser/tst/simple_tests/bare_include_tests/bad_3.sd
Normal file
8
parser/tst/simple_tests/bare_include_tests/bad_3.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - non-existent include should fail
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/does/not/exist {
|
||||
include <does-not-exist/does-not-exist>
|
||||
include <includes/base>
|
||||
}
|
8
parser/tst/simple_tests/bare_include_tests/bad_4.sd
Normal file
8
parser/tst/simple_tests/bare_include_tests/bad_4.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - non-existent include should fail
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/does/not/exist {
|
||||
include <includes/base>
|
||||
include <does-not-exist/does-not-exist>
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1 @@
|
|||
THIS WILL NOT PARSE!
|
|
@ -0,0 +1,6 @@
|
|||
#=DESCRIPTION Valid include
|
||||
#
|
||||
# if parsed stand-alone,
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO} = /foo /bar
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - verify that ignored suffixes are ignored
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
|
||||
include <include_tests/ignored_suffix>
|
||||
|
||||
/does/not/exist {
|
||||
@{FOO} r,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - verify that only suffixes are ignored
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
|
||||
include <include_tests/ignored_suffix_2>
|
||||
|
||||
/does/not/exist {
|
||||
@{FOO} r,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#=DESCRIPTION Valid include
|
||||
#
|
||||
# if parsed stand-alone,
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO} = /foo /bar
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
#=DESCRIPTION A helper for includes_okay.sd
|
||||
#
|
||||
# if parsed standalone,
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
include <includes/fonts>
|
||||
|
||||
/tmp/** r,
|
9
parser/tst/simple_tests/bare_include_tests/ok_1.sd
Normal file
9
parser/tst/simple_tests/bare_include_tests/ok_1.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - basic include of global and local include
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/does/not/exist {
|
||||
#include <includes/base>
|
||||
#include <include_tests/includes_okay_helper.include>
|
||||
#include <includes/base>
|
||||
}
|
8
parser/tst/simple_tests/bare_include_tests/ok_2.sd
Normal file
8
parser/tst/simple_tests/bare_include_tests/ok_2.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - test some "odd" locations of includes
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/does/not/exist {
|
||||
/does/not/exist mr, #include <includes/base> /bin/true Px,
|
||||
include <include_tests/includes_okay_helper.include> #include <includes/base>
|
||||
}
|
9
parser/tst/simple_tests/bare_include_tests/ok_3.sd
Normal file
9
parser/tst/simple_tests/bare_include_tests/ok_3.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - basic include of a directory
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/does/not/exist {
|
||||
include <includes/base>
|
||||
include <includes/>
|
||||
include <includes/base>
|
||||
}
|
7
parser/tst/simple_tests/bare_include_tests/recursive.sd
Normal file
7
parser/tst/simple_tests/bare_include_tests/recursive.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION includes testing - recursive include should fail
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/does/not/exist {
|
||||
include <include_tests/recursive.sd>
|
||||
}
|
7
parser/tst/simple_tests/capability/bad_outside1.sd
Normal file
7
parser/tst/simple_tests/capability/bad_outside1.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION capability rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
capability,
|
||||
|
7
parser/tst/simple_tests/change_profile/bad_outside_1.sd
Normal file
7
parser/tst/simple_tests/change_profile/bad_outside_1.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION change_profile rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
change_profile -> /bin/foo,
|
||||
|
5
parser/tst/simple_tests/dbus/bad_outside_1.sd
Normal file
5
parser/tst/simple_tests/dbus/bad_outside_1.sd
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
#=DESCRIPTION dbus rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
|
||||
dbus name=(SomeService),
|
7
parser/tst/simple_tests/dbus/ok_bind_2.sd
Normal file
7
parser/tst/simple_tests/dbus/ok_bind_2.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION simple dbus implicit bind acceptance test with deny keyword
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile a_profile {
|
||||
deny dbus name=(SomeService),
|
||||
}
|
7
parser/tst/simple_tests/file/bad_bare_file_outside.sd
Normal file
7
parser/tst/simple_tests/file/bad_bare_file_outside.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION bare file rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
file,
|
||||
|
7
parser/tst/simple_tests/file/bad_link_outside.sd
Normal file
7
parser/tst/simple_tests/file/bad_link_outside.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION link rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
deny link /alpha/beta -> /tmp/**,
|
||||
|
7
parser/tst/simple_tests/file/ok_bare_1.sd
Normal file
7
parser/tst/simple_tests/file/ok_bare_1.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=Description bare file rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
deny file,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_outside_1.sd
Normal file
6
parser/tst/simple_tests/mount/bad_outside_1.sd
Normal file
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
#=Description mount rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
mount,
|
7
parser/tst/simple_tests/network/bad_network_outside_1.sd
Normal file
7
parser/tst/simple_tests/network/bad_network_outside_1.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION network rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
network,
|
||||
|
7
parser/tst/simple_tests/ptrace/bad_outside_01.sd
Normal file
7
parser/tst/simple_tests/ptrace/bad_outside_01.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=Description ptrace all rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
ptrace,
|
||||
|
7
parser/tst/simple_tests/rlimits/bad_rlimit_01.sd
Normal file
7
parser/tst/simple_tests/rlimits/bad_rlimit_01.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION realtime time rlimit test with ambiguous unit 'm' which could mean 'ms' or 'minutes'
|
||||
#=EXRESULT FAIL
|
||||
|
||||
profile rlimit {
|
||||
set rlimit rttime <= 60m,
|
||||
}
|
5
parser/tst/simple_tests/rlimits/bad_rlimit_outside_01.sd
Normal file
5
parser/tst/simple_tests/rlimits/bad_rlimit_outside_01.sd
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
#=DESCRIPTION simple cpu rlimit rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
|
||||
set rlimit cpu <= 1024,
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
#=DESCRIPTION simple cpu rlimit test
|
||||
#=DESCRIPTION simple cpu rlimit test, cpu allows default units
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile rlimit {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#=DESCRIPTION simple cpu rlimit test
|
||||
#=DESCRIPTION simple rttime rlimit allows default units
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile rlimit {
|
||||
set rlimit cpu <= 12,
|
||||
set rlimit rttime <= 12,
|
||||
}
|
||||
|
|
7
parser/tst/simple_tests/signal/bad_outside_01.sd
Normal file
7
parser/tst/simple_tests/signal/bad_outside_01.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
#=Description signal rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
|
||||
signal,
|
||||
|
5
parser/tst/simple_tests/unix/bad_outside_1.sd
Normal file
5
parser/tst/simple_tests/unix/bad_outside_1.sd
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
#=DESCRIPTION unix accept rule outside of a profile
|
||||
#=EXRESULT FAIL
|
||||
|
||||
unix accept,
|
8
parser/tst/simple_tests/vars/vars_profile_name_01.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_01.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
/does/not/exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_profile_name_02.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_02.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar baz
|
||||
|
||||
/does/not/exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_profile_name_03.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_03.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can begin with var
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_profile_name_04.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_04.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can begin with var
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar baz
|
||||
|
||||
profile @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_profile_name_05.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_05.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not /exist{@{FOO},} {
|
||||
/does/not/exist r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_profile_name_06.sd
Normal file
8
parser/tst/simple_tests/vars/vars_profile_name_06.sd
Normal file
|
@ -0,0 +1,8 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar baz
|
||||
|
||||
profile /does/not /exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
10
parser/tst/simple_tests/vars/vars_profile_name_07.sd
Normal file
10
parser/tst/simple_tests/vars/vars_profile_name_07.sd
Normal file
|
@ -0,0 +1,10 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can begin with var
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
10
parser/tst/simple_tests/vars/vars_profile_name_08.sd
Normal file
10
parser/tst/simple_tests/vars/vars_profile_name_08.sd
Normal file
|
@ -0,0 +1,10 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can begin with var
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=bar baz
|
||||
|
||||
profile /does/not/exist @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_09.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_09.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION reference variables in name and attachment
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
@{BAR}=baz
|
||||
|
||||
profile /does/not@{BAR} /exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_10.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_10.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar baz
|
||||
@{BAR}=baz
|
||||
|
||||
profile /does/not@{BAR} /exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_11.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_11.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword have var and var attachment
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=/bar /baz
|
||||
@{BAR}=baz foo
|
||||
|
||||
profile /does/not/exist@{BAR} @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
11
parser/tst/simple_tests/vars/vars_profile_name_12.sd
Normal file
11
parser/tst/simple_tests/vars/vars_profile_name_12.sd
Normal file
|
@ -0,0 +1,11 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can expand var and have var attachment
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=bar baz
|
||||
@{BAR}=baz foo
|
||||
|
||||
profile /does/not/exist@{BAR} @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
11
parser/tst/simple_tests/vars/vars_profile_name_13.sd
Normal file
11
parser/tst/simple_tests/vars/vars_profile_name_13.sd
Normal file
|
@ -0,0 +1,11 @@
|
|||
#=DESCRIPTION reference variables that are the profile name and attachment
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=bar
|
||||
@{BAR}=baz
|
||||
|
||||
profile @{BAR} @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
11
parser/tst/simple_tests/vars/vars_profile_name_14.sd
Normal file
11
parser/tst/simple_tests/vars/vars_profile_name_14.sd
Normal file
|
@ -0,0 +1,11 @@
|
|||
#=DESCRIPTION reference variables in rules that also have alternations
|
||||
#=EXRESULT PASS
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=/bar /baz
|
||||
@{BAR}=baz
|
||||
|
||||
profile @{BAR} @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
11
parser/tst/simple_tests/vars/vars_profile_name_15.sd
Normal file
11
parser/tst/simple_tests/vars/vars_profile_name_15.sd
Normal file
|
@ -0,0 +1,11 @@
|
|||
#=DESCRIPTION profiles declared with the profile keyword can begin with var
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=bar baz
|
||||
@{BAR}=baz foo
|
||||
|
||||
profile @{BAR} @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_16.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_16.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in sub profile name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
profile foo@{FOO} {
|
||||
}
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_17.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_17.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in sub profile name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
profile @{FOO} {
|
||||
}
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_18.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_18.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in hat name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
^foo@{FOO} {
|
||||
}
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_19.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_19.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in sub profile name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
profile @{FOO} {
|
||||
}
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_20.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_20.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in sub profile name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
profile foo@{FOO} {
|
||||
}
|
||||
}
|
9
parser/tst/simple_tests/vars/vars_profile_name_21.sd
Normal file
9
parser/tst/simple_tests/vars/vars_profile_name_21.sd
Normal file
|
@ -0,0 +1,9 @@
|
|||
#=DESCRIPTION var in hat name
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{FOO}=bar
|
||||
|
||||
profile /does/not/exist {
|
||||
^@{FOO} {
|
||||
}
|
||||
}
|
10
parser/tst/simple_tests/vars/vars_profile_name_22.sd
Normal file
10
parser/tst/simple_tests/vars/vars_profile_name_22.sd
Normal file
|
@ -0,0 +1,10 @@
|
|||
#=DESCRIPTION all attachment expansions must start with /
|
||||
#=EXRESULT FAIL
|
||||
#=TODO
|
||||
# This test needs check on @{FOO} attachment having leading / post var expansion
|
||||
|
||||
@{FOO}=/bar baz
|
||||
|
||||
profile /does/not/exist @{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
7
parser/tst/simple_tests/vars/vars_profile_name_23.sd
Normal file
7
parser/tst/simple_tests/vars/vars_profile_name_23.sd
Normal file
|
@ -0,0 +1,7 @@
|
|||
#=DESCRIPTION reference variables in profile name is undefined
|
||||
#=EXRESULT FAIL
|
||||
|
||||
|
||||
/does/not/exist@{FOO} {
|
||||
/does/not/exist r,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue