mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
42 Commits
v3.0.13
...
apparmor-3
Author | SHA1 | Date | |
---|---|---|---|
|
21093ca008 | ||
|
3877683071 | ||
|
2bb1abe9c4 | ||
|
e583abc6cc | ||
|
ae60878492 | ||
|
dc5e9352f1 | ||
|
e7d5937213 | ||
|
bdb650bf98 | ||
|
a5523e3c87 | ||
|
602e4f6b9f | ||
|
aa986e3de3 | ||
|
06ead7294a | ||
|
cb9a152e2a | ||
|
6ebf1cb0ef | ||
|
e8b45df48a | ||
|
19b3052b42 | ||
|
6e06d2216b | ||
|
1b0f51d0ce | ||
|
feb4e75e47 | ||
|
f686f7c0ff | ||
|
eeca73e675 | ||
|
fa7eb62c62 | ||
|
11f1928938 | ||
|
deca4adfed | ||
|
c712509d41 | ||
|
0e4540ac91 | ||
|
54c6343b0f | ||
|
ac7c791ca3 | ||
|
09402d2123 | ||
|
dcb3493d19 | ||
|
8d6174e300 | ||
|
d18bc59f49 | ||
|
b69add4f29 | ||
|
7e0465593a | ||
|
e5758891e6 | ||
|
ff6489bfdf | ||
|
0b5a270045 | ||
|
70ade00801 | ||
|
7fc875af09 | ||
|
7e45341ccd | ||
|
d8bb0435c2 | ||
|
4eac7dd99c |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -10,6 +10,17 @@ binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
binutils/po/*.mo
|
||||
changehat/mod_apparmor/.libs
|
||||
changehat/mod_apparmor/mod_apparmor.8
|
||||
changehat/mod_apparmor/mod_apparmor.8.html
|
||||
changehat/mod_apparmor/mod_apparmor.la
|
||||
changehat/mod_apparmor/mod_apparmor.lo
|
||||
changehat/mod_apparmor/mod_apparmor.slo
|
||||
changehat/mod_apparmor/mod_apparmor.so
|
||||
changehat/mod_apparmor/pod2htmd.tmp
|
||||
changehat/pam_apparmor/get_options.o
|
||||
changehat/pam_apparmor/pam_apparmor.o
|
||||
changehat/pam_apparmor/pam_apparmor.so
|
||||
parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
@@ -196,7 +207,6 @@ libraries/libapparmor/testsuite/libaalogparse.test/Makefile
|
||||
libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
|
||||
libraries/libapparmor/testsuite/test_multi/out
|
||||
libraries/libapparmor/testsuite/test_multi_multi-test_multi.o
|
||||
changehat/mod_apparmor/.libs
|
||||
utils/*.8
|
||||
utils/*.8.html
|
||||
utils/*.5
|
||||
|
@@ -1,7 +1,7 @@
|
||||
---
|
||||
image: ubuntu:latest
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf autoconf-archive automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
|
@@ -92,6 +92,13 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
||||
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
||||
fi
|
||||
|
||||
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
|
||||
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
||||
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
||||
,)
|
||||
AC_SUBST([AM_CFLAGS], ["$EXTRA_CFLAGS"])
|
||||
|
||||
AC_OUTPUT(
|
||||
Makefile
|
||||
doc/Makefile
|
||||
|
@@ -39,7 +39,6 @@ include $(COMMONDIR)/Make.rules
|
||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
@@ -47,7 +46,7 @@ scanner.h: scanner.l
|
||||
scanner.c: scanner.l
|
||||
|
||||
af_protos.h:
|
||||
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dM - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
|
||||
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dD - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
|
||||
|
||||
lib_LTLIBRARIES = libapparmor.la
|
||||
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
|
||||
|
@@ -398,6 +398,10 @@ static bool walk_one(const char **str, const struct component *component,
|
||||
i = 0;
|
||||
|
||||
cur++;
|
||||
|
||||
/* Partial match, continue to search */
|
||||
if (i == component->len && !isbrace_space_or_nul(*cur))
|
||||
i = 0;
|
||||
}
|
||||
|
||||
/* Return false if a full match was not found */
|
||||
|
@@ -135,7 +135,7 @@ static int do_test_walk_one(const char **str, const struct component *component,
|
||||
|
||||
static int test_walk_one(void)
|
||||
{
|
||||
struct component c;
|
||||
struct component c = (struct component) { NULL, 0 };
|
||||
const char *str;
|
||||
int rc = 0;
|
||||
|
||||
|
@@ -55,7 +55,7 @@ extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
||||
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
|
||||
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
||||
extern int aa_getcon(char **label, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
|
||||
extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||
int *audit);
|
||||
|
@@ -70,7 +70,10 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
CFLAGS += -flto-partition=none
|
||||
HAVE_FLTO_PARTITION_NONE:=$(shell ${CC} -E -flto-partition=none /dev/null 1>/dev/null 2>&1 && echo true)
|
||||
ifeq ($(HAVE_FLTO_PARTITION_NONE),true)
|
||||
CFLAGS += -flto-partition=none
|
||||
endif
|
||||
|
||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
|
||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
@@ -1786,7 +1786,7 @@ An example AppArmor profile:
|
||||
/usr/lib/** r,
|
||||
/tmp/foo.pid wr,
|
||||
/tmp/foo.* lrw,
|
||||
/@{HOME}/.foo_file rw,
|
||||
@{HOME}/.foo_file rw,
|
||||
/usr/bin/baz Cx -> baz,
|
||||
|
||||
# a comment about foo's hat (subprofile), bar.
|
||||
|
@@ -189,6 +189,19 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
* a b c T
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static Node *simplify_eps_pair(Node *t)
|
||||
{
|
||||
if (dynamic_cast<TwoChildNode *>(t) &&
|
||||
t->child[0] == &epsnode &&
|
||||
t->child[1] == &epsnode) {
|
||||
t->release();
|
||||
return &epsnode;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static void rotate_node(Node *t, int dir)
|
||||
{
|
||||
// (a | b) | c -> a | (b | c)
|
||||
@@ -197,7 +210,9 @@ static void rotate_node(Node *t, int dir)
|
||||
t->child[dir] = left->child[dir];
|
||||
left->child[dir] = left->child[!dir];
|
||||
left->child[!dir] = t->child[!dir];
|
||||
t->child[!dir] = left;
|
||||
|
||||
// check that rotation didn't create (E | E)
|
||||
t->child[!dir] = simplify_eps_pair(left);
|
||||
}
|
||||
|
||||
/* return False if no work done */
|
||||
@@ -209,13 +224,7 @@ int TwoChildNode::normalize_eps(int dir)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = child[!dir];
|
||||
if (dynamic_cast<TwoChildNode *>(c) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
Node *c = simplify_eps_pair(child[!dir]);
|
||||
child[!dir] = child[dir];
|
||||
child[dir] = c;
|
||||
return 1;
|
||||
|
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
#=Description caused an infinite loop in expr normalization
|
||||
#=EXRESULT PASS
|
||||
|
||||
# This test triggers an infinite loop bug in expr normalization
|
||||
# Note: this test might be able to be reduced more but, each element appears
|
||||
# to be required to trigger the bug.
|
||||
# that is the initial var assignment, += with the "comment" at the end
|
||||
# (which is a separate bug), the expansion in the 2nd variable and then
|
||||
# the use of the 2nd variable.
|
||||
# This seems to be due to difference in consistency check between expansion
|
||||
# at parse time and variable expansion.
|
||||
# eg. expanding @{exec_path} manually will result in a failure to parse
|
||||
# see: https://gitlab.com/apparmor/apparmor/-/issues/398
|
||||
|
||||
@{var}=*-linux-gnu*
|
||||
@{var}+=*-suse-linux* #aa:only opensuse
|
||||
|
||||
@{exec_path} = /{,@{var}/}t
|
||||
|
||||
profile test {
|
||||
|
||||
|
||||
@{exec_path} mr,
|
||||
}
|
@@ -28,6 +28,7 @@
|
||||
owner @{run}/user/*/gdm/Xauthority r,
|
||||
owner @{run}/user/*/X11/Xauthority r,
|
||||
owner @{run}/user/*/xauth_* r,
|
||||
owner /tmp/xauth_?????? r,
|
||||
|
||||
# the unix socket to use to connect to the display
|
||||
/tmp/.X11-unix/* rw,
|
||||
|
@@ -31,6 +31,17 @@
|
||||
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
|
||||
/{usr/,}lib/@{multiarch}/security/ r,
|
||||
|
||||
# pam_unix
|
||||
owner /proc/@{pid}/loginuid r,
|
||||
/{,usr/}{,s}bin/unix_chkpwd Px,
|
||||
|
||||
# pam_env
|
||||
@{etc_ro}/environment r,
|
||||
|
||||
# pam_limit
|
||||
@{etc_ro}/security/limits.d/ r,
|
||||
@{etc_ro}/security/limits.d/*.conf r,
|
||||
|
||||
# gssapi
|
||||
@{etc_ro}/gss/mech r,
|
||||
@{etc_ro}/gss/mech.d/ r,
|
||||
|
@@ -96,6 +96,9 @@
|
||||
# best place -- but many profiles require it, and it is quite harmless.
|
||||
@{PROC}/sys/kernel/ngroups_max r,
|
||||
|
||||
# Used to determine if Linux is running in FIPS mode
|
||||
@{PROC}/sys/crypto/fips_enabled r,
|
||||
|
||||
# glibc's sysconf(3) routine to determine free memory, etc
|
||||
@{PROC}/meminfo r,
|
||||
@{PROC}/stat r,
|
||||
|
@@ -13,6 +13,9 @@
|
||||
|
||||
abi <abi/3.0>,
|
||||
|
||||
# Global config of openssl
|
||||
include <abstractions/openssl>
|
||||
|
||||
@{etc_ro}/gcrypt/hwf.deny r,
|
||||
@{etc_ro}/gcrypt/random.conf r,
|
||||
@{PROC}/sys/crypto/fips_enabled r,
|
||||
@@ -24,4 +27,8 @@
|
||||
/etc/crypto-policies/*/*.txt r,
|
||||
/usr/share/crypto-policies/*/*.txt r,
|
||||
|
||||
# Global gnutls config
|
||||
@{etc_ro}/gnutls/config r,
|
||||
@{etc_ro}/gnutls/pkcs11.conf r,
|
||||
|
||||
include if exists <abstractions/crypto.d>
|
||||
|
@@ -20,6 +20,12 @@
|
||||
owner @{HOME}/.cache/mesa_shader_cache/[a-f0-9][a-f0-9]/[0-9a-f]* rw,
|
||||
owner @{HOME}/.cache/mesa_shader_cache/[a-f0-9][a-f0-9]/[0-9a-f]*.tmp rwk,
|
||||
|
||||
owner @{HOME}/.cache/mesa_shader_cache_db/ rw,
|
||||
owner @{HOME}/.cache/mesa_shader_cache_db/index rwk,
|
||||
owner @{HOME}/.cache/mesa_shader_cache_db/part*/ rw,
|
||||
owner @{HOME}/.cache/mesa_shader_cache_db/part*/mesa_cache.db rwk,
|
||||
owner @{HOME}/.cache/mesa_shader_cache_db/part*/mesa_cache.idx rwk,
|
||||
|
||||
# Fallback location when @{HOME}/.cache is not available
|
||||
owner /tmp/Temp-[a-f0-9]*/mesa_shader_cache/ rw,
|
||||
owner /tmp/Temp-[a-f0-9]*/mesa_shader_cache/index rw,
|
||||
|
@@ -62,6 +62,10 @@
|
||||
# have open
|
||||
@{run}/nscd/db* rmix,
|
||||
|
||||
# make libnss-libvirt name resolution work.
|
||||
/var/lib/libvirt/dnsmasq/ r,
|
||||
/var/lib/libvirt/dnsmasq/*.status r,
|
||||
|
||||
# The nss libraries are sometimes used in addition to PAM; make sure
|
||||
# they are available
|
||||
/{usr/,}lib{,32,64}/libnss_*.so* mr,
|
||||
|
@@ -12,8 +12,8 @@
|
||||
|
||||
/etc/ssl/openssl.cnf r,
|
||||
/etc/ssl/openssl-*.cnf r,
|
||||
/etc/ssl/{engdef,engines}.d/ r,
|
||||
/etc/ssl/{engdef,engines}.d/*.cnf r,
|
||||
/etc/ssl/{engdef*,engines*}.d/ r,
|
||||
/etc/ssl/{engdef*,engines*}.d/*.cnf r,
|
||||
/usr/share/ssl/openssl.cnf r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
|
@@ -12,6 +12,7 @@
|
||||
abi <abi/3.0>,
|
||||
|
||||
/etc/samba/* r,
|
||||
/etc/gnutls/config r,
|
||||
/usr/lib*/ldb/*.so mr,
|
||||
/usr/lib*/ldb2/*.so mr,
|
||||
/usr/lib*/ldb2/modules/ldb/*.so mr,
|
||||
|
@@ -13,6 +13,8 @@
|
||||
|
||||
# some services update wtmp, utmp, and lastlog with per-user
|
||||
# connection information
|
||||
/var/lib/wtmpdb/ r,
|
||||
/var/lib/wtmpdb/wtmp.db{,-journal} rwlk,
|
||||
/var/log/lastlog rwk,
|
||||
/var/log/wtmp rwk,
|
||||
/var/log/btmp rwk,
|
||||
|
@@ -24,6 +24,7 @@ profile ping /{usr/,}bin/{,iputils-}ping {
|
||||
|
||||
/{,usr/}bin/{,iputils-}ping mixr,
|
||||
/etc/modules.conf r,
|
||||
@{PROC}/sys/net/ipv6/conf/all/disable_ipv6 r,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/bin.ping>
|
||||
|
@@ -16,12 +16,14 @@ include <tunables/global>
|
||||
profile samba-dcerpcd /usr/lib*/samba/{,samba/}samba-dcerpcd {
|
||||
include <abstractions/samba-rpcd>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
@{run}/{,samba/}samba-dcerpcd.pid rwk,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd mr,
|
||||
|
||||
/usr/lib*/samba/ r,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic Px -> samba-rpcd-classic,
|
||||
/usr/lib*/samba/{,samba/}rpcd_spoolss Px -> samba-rpcd-spoolss,
|
||||
|
||||
|
@@ -13,10 +13,15 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} {
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} {
|
||||
include <abstractions/samba-rpcd>
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} mr,
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/lsarpc wr,
|
||||
@{run}/samba/ncalrpc/np/mdssvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -17,8 +17,18 @@ profile samba-rpcd-classic /usr/lib*/samba/{,samba/}rpcd_classic {
|
||||
include <abstractions/samba-rpcd>
|
||||
include <abstractions/wutmp>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/srvsvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
/dev/urandom rw,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd Px -> samba-dcerpcd,
|
||||
|
||||
@{HOMEDIRS}/** lrwk,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/samba-rpcd-classic>
|
||||
}
|
||||
|
35
profiles/apparmor.d/unix-chkpwd
Normal file
35
profiles/apparmor.d/unix-chkpwd
Normal file
@@ -0,0 +1,35 @@
|
||||
# apparmor.d - Full set of apparmor profiles
|
||||
# Copyright (C) 2019-2021 Mikhail Morfikov
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
# The apparmor.d project comes with several variables and abstractions
|
||||
# that are not part of upstream AppArmor yet. Therefore this profile was
|
||||
# adopted to use abstractions and variables that are available.
|
||||
# Copyright (C) Christian Boltz 2024
|
||||
|
||||
abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile unix-chkpwd /{,usr/}{,s}bin/unix_chkpwd {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
|
||||
# To write records to the kernel auditing log.
|
||||
capability audit_write,
|
||||
|
||||
network netlink raw,
|
||||
|
||||
/{,usr/}{,s}bin/unix_chkpwd mr,
|
||||
|
||||
/etc/shadow r,
|
||||
|
||||
# systemd userdb, used in nspawn
|
||||
/run/host/userdb/*.user r,
|
||||
/run/host/userdb/*.user-privileged r,
|
||||
|
||||
# file_inherit
|
||||
owner /dev/tty[0-9]* rw,
|
||||
|
||||
include if exists <local/unix-chkpwd>
|
||||
}
|
@@ -8,6 +8,7 @@ profile nmbd /usr/{bin,sbin}/nmbd {
|
||||
include <abstractions/samba>
|
||||
|
||||
capability net_bind_service,
|
||||
capability sys_resource,
|
||||
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
|
||||
|
@@ -14,6 +14,7 @@ profile smbd /usr/{bin,sbin}/smbd {
|
||||
include <abstractions/wutmp>
|
||||
|
||||
capability audit_write,
|
||||
capability chown,
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
capability fowner,
|
||||
|
@@ -50,6 +50,15 @@ include <tunables/global>
|
||||
# needed when /proc is mounted with hidepid>=1
|
||||
ptrace (read,trace) peer="unconfined",
|
||||
|
||||
unix (bind) type=stream addr="@*/bus/sshd/system",
|
||||
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/login1
|
||||
interface=org.freedesktop.login1.Manager
|
||||
member=CreateSessionWithPIDFD
|
||||
peer=(label=unconfined),
|
||||
|
||||
/dev/ptmx rw,
|
||||
/dev/pts/[0-9]* rw,
|
||||
/dev/urandom r,
|
||||
|
@@ -85,6 +85,32 @@ runchecktest "ENVIRON (shell script): confined/complain & sensitive env" pass ${
|
||||
# TEST environment filtering still works on setuid apps
|
||||
removeprofile
|
||||
|
||||
tmpfs_dir=${tmpdir}/tmpfs_dir
|
||||
remove_mnt() {
|
||||
mountpoint -q "$tmpfs_dir"
|
||||
if [ $? -eq 0 ] ; then
|
||||
umount "$tmpfs_dir"
|
||||
fi
|
||||
}
|
||||
do_onexit="remove_mnt"
|
||||
|
||||
# setuid apps mounted in a fs with "nosuid" option do not honor those
|
||||
# bits during execution, so run the test in a mounted tmpdir without nosuid
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,OPTIONS -T $tmpdir > /dev/null 2>&1 ; then
|
||||
output="$(${FINDMNT} -no TARGET,OPTIONS -T $tmpdir)"
|
||||
target="$(echo $output | cut -d' ' -f1)"
|
||||
options="$(echo $output | cut -d' ' -f2)"
|
||||
case "$options" in
|
||||
*nosuid* )
|
||||
echo " $target is mounted with nosuid, creating a new mountpoint..."
|
||||
setuid_helper=${tmpfs_dir}/env_check
|
||||
mkdir ${tmpfs_dir}
|
||||
mount -t tmpfs tmpfs ${tmpfs_dir}
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
cp $helper ${setuid_helper}
|
||||
chown nobody ${setuid_helper}
|
||||
chmod u+s ${setuid_helper}
|
||||
|
30
tests/regression/apparmor/mount.inc
Normal file
30
tests/regression/apparmor/mount.inc
Normal file
@@ -0,0 +1,30 @@
|
||||
root_was_shared="no"
|
||||
root="/"
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root and mount "move" operations entirely, so attempt to
|
||||
# detect from which mount point the test is running from, and remount
|
||||
# it MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir > /dev/null 2>&1 ; then
|
||||
output="$(${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir)"
|
||||
root="$(echo $output | cut -d' ' -f1)"
|
||||
if [ "$(echo $output | cut -d' ' -f2)" == "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
# no findmnt or findmnt doesn't know the PROPAGATION column,
|
||||
# but init is systemd so assume rootfs is shared
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as private"
|
||||
mount --make-private $root
|
||||
fi
|
||||
|
||||
prop_cleanup() {
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as shared"
|
||||
mount --make-shared $root
|
||||
fi
|
||||
}
|
@@ -32,7 +32,8 @@ mount_point2=$tmpdir/mountpoint2
|
||||
mount_bad=$tmpdir/mountbad
|
||||
loop_device="unset"
|
||||
fstype="ext2"
|
||||
root_was_shared="no"
|
||||
|
||||
. $bin/mount.inc
|
||||
|
||||
setup_mnt() {
|
||||
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
|
||||
@@ -59,9 +60,7 @@ mount_cleanup() {
|
||||
then
|
||||
/sbin/losetup -d ${loop_device} &> /dev/null
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
mount --make-shared /
|
||||
fi
|
||||
prop_cleanup
|
||||
}
|
||||
do_onexit="mount_cleanup"
|
||||
|
||||
@@ -81,23 +80,6 @@ fi
|
||||
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
|
||||
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED which does
|
||||
# not work with "move", so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily. snippet from pivot_root.sh
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
# no findmnt or findmnt doesn't know the PROPAGATION column,
|
||||
# but init is systemd so assume rootfs is shared
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
mount --make-private /
|
||||
fi
|
||||
|
||||
options=(
|
||||
# default and non-default options
|
||||
"rw,ro"
|
||||
|
@@ -25,7 +25,8 @@ put_old=${new_root}put_old/
|
||||
bad=$tmpdir/BAD/
|
||||
proc=$new_root/proc
|
||||
fstype="ext2"
|
||||
root_was_shared="no"
|
||||
|
||||
. $bin/mount.inc
|
||||
|
||||
pivot_root_cleanup() {
|
||||
mountpoint -q "$proc"
|
||||
@@ -38,29 +39,13 @@ pivot_root_cleanup() {
|
||||
umount "$new_root"
|
||||
fi
|
||||
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as shared'
|
||||
mount --make-shared /
|
||||
fi
|
||||
prop_cleanup
|
||||
}
|
||||
do_onexit="pivot_root_cleanup"
|
||||
|
||||
# systemd mounts / and everything under it MS_SHARED. This breaks
|
||||
# pivot_root entirely, so attempt to detect it, and remount /
|
||||
# MS_PRIVATE temporarily.
|
||||
FINDMNT=/bin/findmnt
|
||||
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
|
||||
if [ "$(${FINDMNT} -no PROPAGATION /)" = "shared" ] ; then
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
|
||||
# no findmnt or findmnt doesn't know the PROPAGATION column,
|
||||
# but init is systemd so assume rootfs is shared
|
||||
root_was_shared="yes"
|
||||
fi
|
||||
if [ "${root_was_shared}" = "yes" ] ; then
|
||||
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as private'
|
||||
mount --make-private /
|
||||
# loopback module must be loaded for mount -o loop to work
|
||||
if [ ! -b /dev/loop0 ] ; then
|
||||
modprobe loop
|
||||
fi
|
||||
|
||||
# Create disk image since pivot_root doesn't allow old root and new root to be
|
||||
|
@@ -27,16 +27,38 @@ bin=$pwd
|
||||
## A. SWAP
|
||||
##
|
||||
|
||||
# check if we can run the test at all
|
||||
swap_file=$tmpdir/swapfile
|
||||
|
||||
# check if we can run the test in tmpdir
|
||||
fstype=$(stat -f --format '%T' "${tmpdir}")
|
||||
if [ "${fstype}" = "tmpfs" ] ; then
|
||||
echo "ERROR: tmpdir '${tmpdir}' is of type tmpfs; can't mount a swapfile on it" 1>&2
|
||||
echo "ERROR: skipping swap tests" 1>&2
|
||||
num_testfailures=1
|
||||
exit
|
||||
# create a mountpoint not tmpfs
|
||||
mount_file=$tmpdir/mountfile
|
||||
mount_point=$tmpdir/mountpoint
|
||||
fstype="ext2"
|
||||
dd if=/dev/zero of=${mount_file} bs=1024 count=900 2> /dev/null
|
||||
/sbin/mkfs -t${fstype} -F ${mount_file} > /dev/null 2> /dev/null
|
||||
/bin/mkdir ${mount_point}
|
||||
|
||||
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
|
||||
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
|
||||
|
||||
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
|
||||
|
||||
swap_file=$mount_point/swapfile
|
||||
fi
|
||||
|
||||
swap_file=$tmpdir/swapfile
|
||||
remove_mnt() {
|
||||
mountpoint -q "${mount_point}"
|
||||
if [ $? -eq 0 ] ; then
|
||||
/bin/umount -t${fstype} ${mount_point}
|
||||
fi
|
||||
if [ -n "$loop_device" ]
|
||||
then
|
||||
/sbin/losetup -d ${loop_device} &> /dev/null
|
||||
fi
|
||||
}
|
||||
do_onexit="remove_mnt"
|
||||
|
||||
# ppc64el wants this to be larger than 640KiB
|
||||
# arm/small machines want this as small as possible
|
||||
|
@@ -104,7 +104,7 @@ def notify_about_new_entries(logfile, wait=0):
|
||||
debug_logger.info(format_event(event, logfile))
|
||||
yield(format_event(event, logfile))
|
||||
except PermissionError:
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.".format(logfile)))
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.").format(logfile))
|
||||
|
||||
else:
|
||||
print(_('Notification emitter started in the background'))
|
||||
@@ -255,18 +255,18 @@ def get_apparmor_events(logfile, since=0):
|
||||
def parse_logdata(logsource):
|
||||
'''Traverse any iterable log source and extract relevant AppArmor events'''
|
||||
|
||||
RE_audit_time_id = '(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
|
||||
RE_kernel_time = '\[[\d\.\s]+\]' # '[ 1612.746129]'
|
||||
RE_type_num = '1[45][0-9][0-9]' # 1400..1599
|
||||
RE_aa_or_op = '(apparmor=|operation=)'
|
||||
RE_audit_time_id = r'(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
|
||||
RE_kernel_time = r'\[[\d\.\s]+\]' # '[ 1612.746129]'
|
||||
RE_type_num = r'1[45][0-9][0-9]' # 1400..1599
|
||||
RE_aa_or_op = r'(apparmor=|operation=)'
|
||||
|
||||
RE_log_parts = [
|
||||
'kernel:\s+(' + RE_kernel_time + '\s+)?(audit:\s+)?type=' + RE_type_num + '\s+' + RE_audit_time_id + RE_aa_or_op, # v2_6 syslog
|
||||
'kernel:\s+(' + RE_kernel_time + '\s+)?' + RE_audit_time_id + 'type=' + RE_type_num + '\s+' + RE_aa_or_op,
|
||||
'type=(AVC|APPARMOR[_A-Z]*|' + RE_type_num + ')\s+' + RE_audit_time_id + '(type=' + RE_type_num + '\s+)?' + RE_aa_or_op, # v2_6 audit and dmesg
|
||||
'type=USER_AVC\s+' + RE_audit_time_id + '.*apparmor=', # dbus
|
||||
'type=UNKNOWN\[' + RE_type_num + '\]\s+' + RE_audit_time_id + RE_aa_or_op,
|
||||
'dbus\[[0-9]+\]:\s+apparmor=', # dbus
|
||||
r'kernel:\s+(' + RE_kernel_time + r'\s+)?(audit:\s+)?type=' + RE_type_num + r'\s+' + RE_audit_time_id + RE_aa_or_op, # v2_6 syslog
|
||||
r'kernel:\s+(' + RE_kernel_time + r'\s+)?' + RE_audit_time_id + r'type=' + RE_type_num + r'\s+' + RE_aa_or_op,
|
||||
r'type=(AVC|APPARMOR[_A-Z]*|' + RE_type_num + r')\s+' + RE_audit_time_id + r'(type=' + RE_type_num + r'\s+)?' + RE_aa_or_op, # v2_6 audit and dmesg
|
||||
r'type=USER_AVC\s+' + RE_audit_time_id + r'.*apparmor=', # dbus
|
||||
r'type=UNKNOWN\[' + RE_type_num + r'\]\s+' + RE_audit_time_id + RE_aa_or_op,
|
||||
r'dbus\[[0-9]+\]:\s+apparmor=', # dbus
|
||||
]
|
||||
|
||||
# Pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing
|
||||
|
@@ -102,13 +102,18 @@ def get_pids_netstat(netstat='netstat'):
|
||||
def read_proc_current(filename):
|
||||
attr = None
|
||||
|
||||
if os.path.exists(filename):
|
||||
try:
|
||||
# don't bother with if os.path.exists(filename): there is always a race
|
||||
with apparmor.common.open_file_read(filename) as current:
|
||||
for line in current:
|
||||
line = line.strip()
|
||||
if line.endswith(' (complain)', 1) or line.endswith(' (enforce)', 1) or line.endswith(' (kill)', 1): # enforce at least one char as profile name
|
||||
# intentionally not checking for '(unconfined)', because $binary confined by $profile (unconfined) would look very confusing
|
||||
attr = line
|
||||
except OSError:
|
||||
# just ignore errors atm
|
||||
# print("Error trying to open {filename}")
|
||||
return None
|
||||
|
||||
return attr
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import re
|
||||
import sys
|
||||
import time
|
||||
import LibAppArmor
|
||||
import apparmor.ui as aaui
|
||||
from apparmor.common import AppArmorException, AppArmorBug, hasher, open_file_read, split_name, DebugLogger
|
||||
|
||||
# setup module translations
|
||||
@@ -82,7 +83,13 @@ class ReadLog:
|
||||
if sys.version_info < (3, 0):
|
||||
# parse_record fails with u'foo' style strings hence typecasting to string
|
||||
msg = str(msg)
|
||||
event = LibAppArmor.parse_record(msg)
|
||||
|
||||
try:
|
||||
event = LibAppArmor.parse_record(msg)
|
||||
except TypeError:
|
||||
aaui.UI_Important(_("WARNING: Cannot process log message, skipping entry. Make sure log is plaintext."))
|
||||
return None
|
||||
|
||||
ev = dict()
|
||||
ev['resource'] = event.info
|
||||
ev['active_hat'] = event.active_hat
|
||||
|
@@ -26,7 +26,7 @@ allow_exec_transitions = ('ix', 'ux', 'Ux', 'px', 'Px', 'cx', 'Cx') #
|
||||
allow_exec_fallback_transitions = ('pix', 'Pix', 'cix', 'Cix', 'pux', 'PUx', 'cux', 'CUx') # 3 chars - len relevant for split_perms()
|
||||
deny_exec_transitions = ('x')
|
||||
file_permissions = ('m', 'r', 'w', 'a', 'l', 'k', 'link', 'subset') # also defines the write order
|
||||
|
||||
implicit_all_permissions = ('m', 'r', 'w', 'l', 'k')
|
||||
|
||||
|
||||
class FileRule(BaseRule):
|
||||
@@ -234,7 +234,7 @@ class FileRule(BaseRule):
|
||||
if self.all_paths and self.all_perms and not path and not perms and not target:
|
||||
return('%s%s%sfile,%s' % (space, self.modifiers_str(), owner, self.comment)) # plain 'file,' rule
|
||||
elif not self.all_paths and not self.all_perms and path and perms:
|
||||
return('%s%s%s%s%s%s,%s' % (space, self.modifiers_str(), file_keyword, owner, path_and_perms, target, self.comment))
|
||||
return ('%s%s%s%s%s%s,%s' % (space, self.modifiers_str(), owner, file_keyword, path_and_perms, target, self.comment))
|
||||
else:
|
||||
raise AppArmorBug('Invalid combination of path and perms in file rule - either specify path and perms, or none of them')
|
||||
|
||||
@@ -366,8 +366,21 @@ class FileRule(BaseRule):
|
||||
|
||||
old_mode = ''
|
||||
if self.original_perms:
|
||||
original_perms_all = self._join_given_perms(self.original_perms['allow']['all'], None)
|
||||
original_perms_owner = self._join_given_perms(self.original_perms['allow']['owner'] - self.original_perms['allow']['all'], None) # only list owner perms that are not covered by other perms
|
||||
original_perms_set = {}
|
||||
for who in ['all', 'owner']:
|
||||
original_perms_set[who] = {}
|
||||
original_perms_set[who]['perms'] = self.original_perms['allow'][who]
|
||||
original_perms_set[who]['exec_perms'] = None
|
||||
|
||||
if self.original_perms['allow'][who] == FileRule.ALL:
|
||||
original_perms_set[who]['perms'] = set(implicit_all_permissions)
|
||||
original_perms_set[who]['exec_perms'] = 'ix'
|
||||
|
||||
original_perms_all = self._join_given_perms(original_perms_set['all']['perms'],
|
||||
original_perms_set['all']['exec_perms'])
|
||||
original_perms_owner = self._join_given_perms(
|
||||
original_perms_set['owner']['perms'] - original_perms_set['all']['perms'], # only list owner perms that are not covered by other perms
|
||||
original_perms_set['owner']['exec_perms'])
|
||||
|
||||
if original_perms_all and original_perms_owner:
|
||||
old_mode = '%s + owner %s' % (original_perms_all, original_perms_owner)
|
||||
|
@@ -21,16 +21,17 @@ COMMONDIR=../../common/
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
LD_LIBRARY_PATH=
|
||||
PYTHONPATH=
|
||||
LD_LIBRARY_PATH?=
|
||||
PYTHONPATH?=
|
||||
CONFDIR=
|
||||
BASEDIR=
|
||||
PARSER=
|
||||
else
|
||||
PYTHON_DIST_BUILD_PATH = ../../libraries/libapparmor/swig/python/build/$$($(PYTHON) ../../libraries/libapparmor/swig/python/test/buildpath.py)
|
||||
LIBAPPARMOR_PATH=../../libraries/libapparmor/src/.libs/
|
||||
LD_LIBRARY_PATH=$(LIBAPPARMOR_PATH):$(PYTHON_DIST_BUILD_PATH)
|
||||
PYTHONPATH=..:$(PYTHON_DIST_BUILD_PATH)
|
||||
LIBAPPARMOR_BASEDIR?=../../libraries/libapparmor
|
||||
PYTHON_DIST_BUILD_PATH ?= $(LIBAPPARMOR_BASEDIR)/swig/python/build/$$($(PYTHON) $(LIBAPPARMOR_BASEDIR)/swig/python/test/buildpath.py)
|
||||
LIBAPPARMOR_PATH?=$(LIBAPPARMOR_BASEDIR)/src/.libs/
|
||||
LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH):$(LIBAPPARMOR_PATH):$(PYTHON_DIST_BUILD_PATH)
|
||||
PYTHONPATH:=$(PYTHONPATH):..:$(PYTHON_DIST_BUILD_PATH)
|
||||
CONFDIR=$(CURDIR)
|
||||
BASEDIR=../../profiles/apparmor.d
|
||||
PARSER=../../parser/apparmor_parser
|
||||
|
@@ -11,11 +11,13 @@
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import pwd
|
||||
import signal
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
|
||||
from common_test import AATest, setup_all_loops, setup_aa
|
||||
import apparmor.aa as aa
|
||||
@@ -64,8 +66,8 @@ def cmd(command):
|
||||
|
||||
class AANotifyTest(AATest):
|
||||
|
||||
def AASetup(self):
|
||||
'''Create temporary log file with 30 enties of different age'''
|
||||
def create_logfile_contents(self, _time):
|
||||
'''Create temporary log file with 30 entries of different age'''
|
||||
|
||||
test_logfile_contents_999_days_old = \
|
||||
'''Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit({epoch}:113): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/bin/uname" pid=4097 comm="sh" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/bin/uname"
|
||||
@@ -78,7 +80,7 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
|
||||
'''.format(epoch=round(time.time(), 3) - 60*60*24*999)
|
||||
'''.format(epoch=round(_time, 3) - 60 * 60 * 24 * 999)
|
||||
|
||||
test_logfile_contents_30_days_old = \
|
||||
'''Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit({epoch}:113): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/bin/uname" pid=4097 comm="sh" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/bin/uname"
|
||||
@@ -91,7 +93,7 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
|
||||
'''.format(epoch=round(time.time(), 3) - 60*60*24*30)
|
||||
'''.format(epoch=round(_time, 3) - 60 * 60 * 24 * 30)
|
||||
|
||||
test_logfile_contents_unrelevant_entries = \
|
||||
'''Feb 1 19:35:44 XPS-13-9370 kernel: [99848.048761] audit: type=1400 audit(1549042544.968:72): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/6350/usr/lib/snapd/snap-confine" pid=12871 comm="apparmor_parser"
|
||||
@@ -110,24 +112,65 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
|
||||
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
|
||||
'''.format(epoch=round(time.time(), 3))
|
||||
'''.format(epoch=round(_time, 3))
|
||||
|
||||
handle, self.test_logfile = tempfile.mkstemp(prefix='test-aa-notify-')
|
||||
os.close(handle)
|
||||
handle = open(self.test_logfile, "w+")
|
||||
handle.write(
|
||||
test_logfile_contents_999_days_old +
|
||||
test_logfile_contents_30_days_old +
|
||||
test_logfile_contents_unrelevant_entries +
|
||||
test_logfile_contents_0_seconds_old
|
||||
)
|
||||
handle.close()
|
||||
return test_logfile_contents_999_days_old \
|
||||
+ test_logfile_contents_30_days_old \
|
||||
+ test_logfile_contents_unrelevant_entries \
|
||||
+ test_logfile_contents_0_seconds_old
|
||||
|
||||
def AASetup(self):
|
||||
file_current, self.test_logfile_current = tempfile.mkstemp(prefix='test-aa-notify-')
|
||||
os.close(file_current)
|
||||
file_current = open(self.test_logfile_current, "w+")
|
||||
|
||||
file_last_login, self.test_logfile_last_login = tempfile.mkstemp(prefix='test-aa-notify-')
|
||||
os.close(file_last_login)
|
||||
file_last_login = open(self.test_logfile_last_login, "w+")
|
||||
|
||||
current_time_contents = self.create_logfile_contents(time.time())
|
||||
file_current.write(current_time_contents)
|
||||
file_current.close()
|
||||
|
||||
if os.path.isfile('/var/log/wtmp'):
|
||||
if os.name == "posix":
|
||||
username = pwd.getpwuid(os.geteuid()).pw_name
|
||||
else:
|
||||
username = os.environ.get('USER')
|
||||
if not username and hasattr(os, 'getlogin'):
|
||||
username = os.getlogin()
|
||||
if 'SUDO_USER' in os.environ:
|
||||
username = os.environ.get('SUDO_USER')
|
||||
|
||||
return_code, output = cmd(['last', username, '--time-format', 'iso'])
|
||||
output = output.split('\n')[0] # the first line is enough
|
||||
# example of output (util-linux last command):
|
||||
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
|
||||
# example of output (wtmpdb last command, local login):
|
||||
# ubuntu tty7 2025-01-15T09:32:49-0800 - still logged in
|
||||
# example of output (wtmpdb last command, remote login)
|
||||
# ubuntu tty7 192.168.122.1 2024-01-05T14:29:11-03:00 gone - no logout
|
||||
if output.startswith(username):
|
||||
# Check both possible columns for the date
|
||||
try:
|
||||
last_login = output.split()[3]
|
||||
last_login_epoch = datetime.fromisoformat(last_login).timestamp()
|
||||
except (IndexError, ValueError):
|
||||
last_login = output.split()[2]
|
||||
last_login_epoch = datetime.fromisoformat(last_login).timestamp()
|
||||
|
||||
# add 60 seconds to the epoch so that the time in the logs are AFTER login time
|
||||
last_login_contents = self.create_logfile_contents(last_login_epoch + 60)
|
||||
file_last_login.write(last_login_contents)
|
||||
file_last_login.close()
|
||||
|
||||
def AATeardown(self):
|
||||
'''Remove temporary log file after tests ended'''
|
||||
|
||||
if self.test_logfile and os.path.exists(self.test_logfile):
|
||||
os.remove(self.test_logfile)
|
||||
if self.test_logfile_current and os.path.exists(self.test_logfile_current):
|
||||
os.remove(self.test_logfile_current)
|
||||
if self.test_logfile_last_login and os.path.exists(self.test_logfile_last_login):
|
||||
os.remove(self.test_logfile_last_login)
|
||||
|
||||
# The Perl aa-notify script was written so, that it will checked for kern.log
|
||||
# before printing help when invoked without arguments (sic!).
|
||||
@@ -186,7 +229,7 @@ Display AppArmor notifications or messages for DENIED entries.
|
||||
expected_return_code = 0
|
||||
expected_output_has = 'AppArmor denials: 20 (since'
|
||||
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-s', '100'])
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_current, '-s', '100'])
|
||||
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)
|
||||
self.assertEqual(expected_return_code, return_code, result + output)
|
||||
result = 'Got output "%s", expected "%s"\n' % (output, expected_output_has)
|
||||
@@ -199,7 +242,7 @@ Display AppArmor notifications or messages for DENIED entries.
|
||||
expected_return_code = 0
|
||||
expected_output_has = 'AppArmor denials: 10 (since'
|
||||
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-l'])
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_last_login, '-l'])
|
||||
if "ERROR: Could not find last login" in output:
|
||||
self.skipTest('Could not find last login')
|
||||
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)
|
||||
@@ -273,9 +316,9 @@ Name: /usr/bin/file
|
||||
Denied: rm
|
||||
Logfile: {logfile}
|
||||
|
||||
AppArmor denials: 10 (since'''.format(logfile=self.test_logfile)
|
||||
AppArmor denials: 10 (since'''.format(logfile=self.test_logfile_last_login)
|
||||
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-l', '-v'])
|
||||
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_last_login, '-l', '-v'])
|
||||
if "ERROR: Could not find last login" in output:
|
||||
self.skipTest('Could not find last login')
|
||||
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)
|
||||
|
@@ -393,6 +393,9 @@ class WriteFileTest(AATest):
|
||||
(' deny file /foo r,' , 'deny file /foo r,'),
|
||||
(' deny file /foo wr,' , 'deny file /foo rw,'),
|
||||
(' allow file /foo Pxrm -> bar,' , 'allow file /foo mrPx -> bar,'),
|
||||
(' deny owner file /foo r,' , 'deny owner file /foo r,'),
|
||||
(' deny owner file /foo wr,' , 'deny owner file /foo rw,'),
|
||||
(' allow owner file /foo Pxrm -> bar,' , 'allow owner file /foo mrPx -> bar,'),
|
||||
(' deny owner /foo r,' , 'deny owner /foo r,'),
|
||||
(' deny owner /foo wr,' , 'deny owner /foo rw,'),
|
||||
(' allow owner /foo Pxrm -> bar,' , 'allow owner /foo mrPx -> bar,'),
|
||||
@@ -407,6 +410,9 @@ class WriteFileTest(AATest):
|
||||
(' deny file r /foo,' , 'deny file r /foo,'),
|
||||
(' deny file wr /foo ,' , 'deny file rw /foo,'),
|
||||
(' allow file Pxmr /foo -> bar,' , 'allow file mrPx /foo -> bar,'),
|
||||
(' deny owner file r /foo ,' , 'deny owner file r /foo,'),
|
||||
(' deny owner file wr /foo ,' , 'deny owner file rw /foo,'),
|
||||
(' allow owner file Pxrm /foo -> bar,' , 'allow owner file mrPx /foo -> bar,'),
|
||||
(' deny owner r /foo ,' , 'deny owner r /foo,'),
|
||||
(' deny owner wr /foo ,' , 'deny owner rw /foo,'),
|
||||
(' allow owner Pxrm /foo -> bar,' , 'allow owner mrPx /foo -> bar,'),
|
||||
@@ -835,6 +841,17 @@ class FileLogprofHeaderTest(AATest):
|
||||
obj.original_perms = {'allow': { 'all': set(), 'owner': set()}}
|
||||
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('New Mode'), _('rw')])
|
||||
|
||||
def test_implicit_original_perms(self):
|
||||
obj = FileRule._parse('/foo rw,')
|
||||
obj.original_perms = {'allow': {'all': FileRule.ALL, 'owner': set()}}
|
||||
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('Old Mode'), _('mrwlkix'), _('New Mode'), _('rw')])
|
||||
|
||||
def test_owner_implicit_original_perms(self):
|
||||
obj = FileRule._parse('/foo rw,')
|
||||
obj.original_perms = {'allow': {'all': set(), 'owner': FileRule.ALL}}
|
||||
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('Old Mode'), _('owner mrwlkix'), _('New Mode'), _('rw')])
|
||||
|
||||
|
||||
class FileEditHeaderTest(AATest):
|
||||
def _run_test(self, params, expected):
|
||||
rule_obj = FileRule.parse(params)
|
||||
|
@@ -159,8 +159,8 @@ syn match sdRLimit /\v^\s*set\s+rlimit\s+(nofile|ofile|nproc|rtprio)\s+\<\=\s+[0
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+(locks|sigpending)\s+\<\=\s+[0-9]+@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+(fsize|data|stack|core|rss|as|memlock|msgqueue)\s+\<\=\s+[0-9]+([KMG]B)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+nice\s+\<\=\s+(-1?[0-9]|-20|1?[0-9])@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+cpu\s+\<\=\s+[0-9]+(seconds|minutes|hours|days)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+rttime\s+\<\=\s+[0-9]+(ms|seconds|minutes)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+cpu\s+\<\=\s+[0-9]+\s*(s|sec|second|seconds|min|minute|minutes|h|hour|hours|d|day|days|week|weeks)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+rttime\s+\<\=\s+[0-9]+\s*(us|microsecond|microseconds|ms|millisecond|milliseconds|s|sec|second|seconds|min|minute|minutes|h|hour|hours|d|day|days|week|weeks)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+(cpu|rttime|nofile|nproc|rtprio|locks|sigpending|fsize|data|stack|core|rss|as|memlock|msgqueue|nice)\s+\<\=\s+infinity@@EOL@@/ contains=sdComment
|
||||
|
||||
" link rules
|
||||
|
Reference in New Issue
Block a user