Signed-off-by: Oskari Rauta <oskari.rauta@gmail.com>lilik-openwrt-22.03
@ -0,0 +1,216 @@ | |||
# SPDX-License-Identifier: GPL-2.0-only | |||
include $(TOPDIR)/rules.mk | |||
PKG_NAME:=apparmor | |||
PKG_VERSION:=3.0.1 | |||
PKG_RELEASE:=$(AUTORELEASE) | |||
PKG_SOURCE_PROTO:=git | |||
PKG_SOURCE_URL:=https://gitlab.com/apparmor/apparmor.git | |||
PKG_SOURCE_VERSION:=0325ba06da6eeb5acf3e568063a08136fd0913e0 | |||
PKG_MIRROR_HASH:=303ceca041ad8023fa44cdda366448d60b6299790266834b4078d30b70ad27f9 | |||
PKG_LICENSE:=GPL-2.0-only | |||
PKG_LICENSE_FILES:=LICENSE | |||
PKG_MAINTAINER:=Oskari Rauta <oskari.rauta@gmail.com> | |||
BUILDONLY:=1 | |||
PKG_BUILD_DEPENDS:=swig/host | |||
HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:=setuptools-scm | |||
include $(INCLUDE_DIR)/package.mk | |||
include $(INCLUDE_DIR)/nls.mk | |||
include ../../../packages/lang/python/python3-package.mk | |||
define Package/apparmor/Default | |||
SECTION:=utils | |||
CATEGORY:=Utilities | |||
SUBMENU:=AppArmor | |||
URL:=https://apparmor.net | |||
endef | |||
define Package/libapparmor | |||
TITLE:=AppArmor library | |||
SECTION:=libs | |||
CATEGORY:=Libraries | |||
URL:=https://apparmor.net | |||
endef | |||
define Package/python3-apparmor | |||
TITLE:=AppArmor Python bindings | |||
SECTION:=lang | |||
CATEGORY:=Languages | |||
SUBMENU:=Python | |||
URL:=https://apparmor.net | |||
DEPENDS:=+libapparmor +python3 | |||
endef | |||
define Package/apparmor-utils | |||
$(call Package/apparmor/Default) | |||
TITLE:=AppArmor utils | |||
DEPENDS:=$(INTL_DEPENDS) +libapparmor +python3-apparmor +python3 +python3-readline +python3-psutil +ss +findutils-xargs | |||
endef | |||
define Package/apparmor-profiles | |||
$(call Package/apparmor/Default) | |||
TITLE:=AppArmor default profiles | |||
endef | |||
define Package/libapparmor/description | |||
Library to support AppArmor userspace utilities | |||
endef | |||
define Package/apparmor-utils/description | |||
AppArmor application security system init script and | |||
userspace utils to assist with AppArmor profile management | |||
endef | |||
define Package/apparmor-profiles/description | |||
A collection of profiles for the AppArmor application security system | |||
endef | |||
CONFIGURE_PATH=libraries/libapparmor | |||
TARGET_LDFLAGS += \ | |||
-L$(PYTHON3_LIB_DIR) | |||
CONFIGURE_VARS += \ | |||
SHELL=$(bash) \ | |||
PYTHON_VERSION=$(PYTHON3_VERSION) \ | |||
PYTHON_VERSIONS=$(PYTHON3) \ | |||
PYTHON=$(PYTHON3) \ | |||
PYTHON_CONFIG=$(STAGING_DIR_ROOT)/host/bin/python$(PYTHON3_VERSION)-config \ | |||
PYTHON_LDFLAGS="-L$(STAGING_DIR)/usr/lib -L$(PYTHON3_LIB_DIR)" \ | |||
PYTHON_CPPFLAGS="-I$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION)" \ | |||
PYTHON_LDFLAGS="-I$(PYTHON3_INC_DIR) -L$(STAGING_DIR)/usr/lib -L$(PYTHON3_LIB_DIR)" \ | |||
PYTHON_EXTRA_LDFLAGS="-L$(STAGING_DIR)/usr/lib -L$(PYTHON3_LIB_DIR)/config-$(PYTHON3_VERSION) -lpthread -ldl -lm -lz -lpython$(PYTHON3_VERSION)" \ | |||
ac_cv_path_PYTHON_CONFIG="$(STAGING_DIR)/host/bin/python$(PYTHON3_VERSION)-config" | |||
CONFIGURE_ARGS += \ | |||
--with-python \ | |||
--without-perl \ | |||
--without-ruby \ | |||
--disable-man-pages | |||
ifeq ($(CONFIG_BUILD_NLS),y) | |||
MAKE_VARS += WITH_LIBINTL=1 | |||
MAKE_FLAGS += WITH_LIBINTL=1 | |||
endif | |||
APPARMOR_CFLAGS = -I$(PKG_BUILD_DIR)/libraries/libapparmor/include | |||
APPARMOR_LDFLAGS = -L$(PKG_BUILD_DIR)/libraries/libapparmor/src/.libs | |||
define Build/Configure | |||
$(MAKE) -C $(PKG_BUILD_DIR)/libraries/libapparmor configure | |||
$(RM) $(PKG_BUILD_DIR)/libraries/libapparmor/Makefile | |||
$(SED) 's#ac_cv_path_PYTHON_CONFIG=#ac_cv_path_X_PYTHON_CONFIG=#g' $(PKG_BUILD_DIR)/libraries/libapparmor/configure | |||
$(call Build/Configure/Default) | |||
endef | |||
define Build/Compile | |||
# Building libapparmor | |||
+$(MAKE_VARS) \ | |||
CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/libraries/libapparmor \ | |||
$(MAKE_FLAGS) | |||
# Building parser | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) \ | |||
CFLAGS="$(TARGET_CFLAGS) $(APPARMOR_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS) $(APPARMOR_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS) $(APPARMOR_LDFLAGS) -lgcc_s" USE_SYSTEM=0 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/parser \ | |||
$(MAKE_FLAGS) apparmor_parser | |||
# Building binutils | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) \ | |||
CFLAGS="$(TARGET_CFLAGS) $(APPARMOR_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS) $(APPARMOR_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS) $(APPARMOR_LDFLAGS)" USE_SYSTEM=0 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/binutils \ | |||
$(MAKE_FLAGS) | |||
# Building utils | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) \ | |||
CFLAGS="$(TARGET_CFLAGS) $(APPARMOR_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS) $(APPARMOR_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS) $(APPARMOR_LDFLAGS)" USE_SYSTEM=0 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/utils \ | |||
$(MAKE_FLAGS) | |||
# Building profiles | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) \ | |||
CFLAGS="$(TARGET_CFLAGS) $(APPARMOR_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS) $(APPARMOR_CFLAGS")" LDFLAGS="$(TARGET_LDFLAGS) $(APPARMOR_LDFLAGS)" USE_SYSTEM=0 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/profiles \ | |||
$(MAKE_FLAGS) | |||
endef | |||
define Build/Install | |||
# Make sure we have python's setup tools installed | |||
$(if $(PYTHON3_PKG_HOST_PIP_INSTALL_ARGS), \ | |||
$(call HostPython3/PipInstall,$(PYTHON3_PKG_HOST_PIP_INSTALL_ARGS)) \ | |||
) | |||
$(INSTALL_DIR) $(PKG_INSTALL_DIR)-libapparmor $(PKG_INSTALL_DIR)-utils $(PKG_INSTALL_DIR)-profiles | |||
# Installing libapparmor | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) VERSION=$(PYTHON3_VERSION) \ | |||
CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" \ | |||
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/libraries/libapparmor \ | |||
$(MAKE_FLAGS) DESTDIR="$(PKG_INSTALL_DIR)-libapparmor" install | |||
# Installing parser | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) VERSION=$(PYTHON3_VERSION) \ | |||
CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" USE_SYSTEM=1 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/parser \ | |||
$(MAKE_FLAGS) DESTDIR="$(PKG_INSTALL_DIR)-utils" install | |||
# Installing binutils | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) VERSION=$(PYTHON3_VERSION) \ | |||
CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" USE_SYSTEM=1 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/binutils \ | |||
$(MAKE_FLAGS) DESTDIR="$(PKG_INSTALL_DIR)-utils" install | |||
# Installing utils | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) VERSION=$(PYTHON3_VERSION) \ | |||
CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" USE_SYSTEM=1 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/utils \ | |||
$(MAKE_FLAGS) DESTDIR="$(PKG_INSTALL_DIR)-utils" install | |||
# Installing profiles | |||
+$(MAKE_VARS) PYTHON=$(HOST_PYTHON) VERSION=$(PYTHON3_VERSION) \ | |||
CFLAGS="$(TARGET_CFLAGS)" LDFLAGS="$(TARGET_LDFLAGS)" USE_SYSTEM=1 $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/profiles \ | |||
$(MAKE_FLAGS) DESTDIR="$(PKG_INSTALL_DIR)-profiles" install | |||
endef | |||
define Package/libapparmor/install | |||
$(INSTALL_DIR) $(1)/usr/lib | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-libapparmor/usr/lib/libapparmor.so.1 $(1)/usr/lib/ | |||
$(LN) libapparmor.so.1 $(1)/usr/lib/libapparmor.so | |||
endef | |||
define Package/python3-apparmor/install | |||
$(INSTALL_DIR) \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-libapparmor/usr/lib/python$(PYTHON3_VERSION)/site-packages/*.egg-info \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages/ | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-libapparmor/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor/*.py \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-libapparmor/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor/*.so \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor/ | |||
$(LN) -s _LibAppArmor.cpython-$(PYTHON3_VERSION_MAJOR)$(PYTHON3_VERSION_MINOR).so \ | |||
$(1)/usr/lib/python$(PYTHON3_VERSION)/site-packages/LibAppArmor/_LibAppArmor.so | |||
endef | |||
define Package/apparmor-utils/install | |||
$(INSTALL_DIR) $(1)/etc/apparmor $(1)/usr/sbin $(1)/sbin | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-utils/sbin/apparmor_parser $(1)/sbin/ | |||
$(INSTALL_CONF) $(PKG_INSTALL_DIR)-utils/etc/apparmor/*.conf $(1)/etc/apparmor/ | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/etc/apparmor/severity.db $(1)/etc/apparmor/ | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-utils/sbin/apparmor_parser $(1)/sbin/ | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-utils/usr/bin/{aa-exec,aa-easyprof,aa-enabled,aa-features-abi} $(1)/usr/sbin/ | |||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)-utils/usr/sbin/{aa-audit,aa-autodep,aa-cleanprof,aa-complain,aa-decode,aa-disable,aa-enforce,aa-genprof,aa-logprof,aa-mergeprof,aa-notify,aa-remove-unknown,aa-status,aa-unconfined} $(1)/usr/sbin/ | |||
$(LN) aa-status $(1)/usr/sbin/apparmor_status | |||
$(INSTALL_DIR) $(1)/usr/share/apparmor/easyprof/templates $(1)/usr/share/apparmor/easyprof/policygroups | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/usr/share/apparmor/easyprof/templates/* $(1)/usr/share/apparmor/easyprof/templates/ | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/usr/share/apparmor/easyprof/policygroups/* $(1)/usr/share/apparmor/easyprof/policygroups/ | |||
$(INSTALL_DIR) $(1)/usr/lib/python3.9/site-packages $(1)/usr/lib/python3.9/site-packages/apparmor $(1)/usr/lib/python3.9/site-packages/apparmor/rule | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/usr/lib/python3.9/site-packages/*.egg-info \ | |||
$(1)/usr/lib/python3.9/site-packages/ | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/usr/lib/python3.9/site-packages/apparmor/*.py \ | |||
$(1)/usr/lib/python3.9/site-packages/apparmor/ | |||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)-utils/usr/lib/python3.9/site-packages/apparmor/rule/*.py \ | |||
$(1)/usr/lib/python3.9/site-packages/apparmor/rule | |||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/lib/functions | |||
$(INSTALL_BIN) ./files/apparmor.sh $(1)/lib/functions/ | |||
$(INSTALL_BIN) ./files/apparmor.init $(1)/etc/init.d/apparmor | |||
endef | |||
define Package/apparmor-profiles/install | |||
$(INSTALL_DIR) $(1)/etc/apparmor.d $(1)/usr/share/apparmor/extra-profiles | |||
$(CP) -aR $(PKG_INSTALL_DIR)-profiles/etc/apparmor.d/** $(1)/etc/apparmor.d/ | |||
$(INSTALL_CONF) $(PKG_INSTALL_DIR)-profiles/usr/share/apparmor/extra-profiles/** $(1)/usr/share/apparmor/extra-profiles/ | |||
endef | |||
$(eval $(call BuildPackage,libapparmor)) | |||
$(eval $(call BuildPackage,python3-apparmor)) | |||
$(eval $(call BuildPackage,apparmor-utils)) | |||
$(eval $(call BuildPackage,apparmor-profiles)) |
@ -0,0 +1,22 @@ | |||
#!/bin/sh /etc/rc.common | |||
START=75 | |||
USE_PROCD=1 | |||
. /lib/functions/apparmor.sh | |||
restart() { | |||
apparmor_restart | |||
} | |||
start_service() { | |||
apparmor_start | |||
} | |||
stop_service() { | |||
apparmor_stop | |||
} | |||
reload_service() { | |||
apparmor_reload | |||
} |
@ -0,0 +1,380 @@ | |||
#!/bin/sh | |||
log_write() { | |||
local facility=kern.$1 | |||
logger -t AppArmor -p $facility "$2" | |||
} | |||
AA_STATUS=/usr/sbin/aa-status | |||
SECURITYFS=/sys/kernel/security | |||
SFS_MOUNTPOINT="${SECURITYFS}/apparmor" | |||
PARSER=/sbin/apparmor_parser | |||
PARSER_OPTS= | |||
ADDITIONAL_PROFILE_DIR= | |||
[ -d /etc/apparmor.d ] && PROFILE_DIRS=/etc/apparmor.d || | |||
log_write warning "Unable to find profiles: /etc/apparmor.d" | |||
[ -n "$ADDITIONAL_PROFILE_DIR" ] && [ -d "$ADDITIONAL_PROFILE_DIR" ] && | |||
PROFILE_DIRS="$PROFILE_DIRS $ADDITIONAL_PROFILE_DIR" | |||
dir_is_empty() { | |||
[ "$(du -s $1 | cut -f 1)" -eq 0 ] && return 0 || return 1 | |||
} | |||
profiles_loaded_count() { | |||
[ -f ${SFS_MOUNTPOINT}/profiles ] && | |||
return $(cat "${SFS_MOUNTPOINT}/profiles" | wc -l) || return 0 | |||
} | |||
is_profiles_loaded() { | |||
[ -f ${SFS_MOUNTPOINT}/profiles ] && { | |||
rc=$(cat "${SFS_MOUNTPOINT}/profiles" | wc -l) | |||
[ "$rc" -ne 0 ] && return 0 || return 1 | |||
} | |||
return 1 | |||
} | |||
is_container_with_internal_policy() { | |||
local ns_stacked_path="${SFS_MOUNTPOINT}/.ns_stacked" | |||
local ns_name_path="${SFS_MOUNTPOINT}/.ns_name" | |||
local ns_stacked | |||
local ns_name | |||
if ! [ -f "$ns_stacked_path" ] || ! [ -f "$ns_name_path" ]; then | |||
return 1 | |||
fi | |||
read -r ns_stacked < "$ns_stacked_path" | |||
if [ "$ns_stacked" != "yes" ]; then | |||
return 1 | |||
fi | |||
# LXD and LXC set up AppArmor namespaces starting with "lxd-" and | |||
# "lxc-", respectively. Return non-zero for all other namespace | |||
# identifiers. | |||
read -r ns_name < "$ns_name_path" | |||
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \ | |||
[ "${ns_name#lxc-*}" = "$ns_name" ]; then | |||
return 1 | |||
fi | |||
return 0 | |||
} | |||
skip_profile() { | |||
local profile="$1" | |||
if [ "${profile%.rpmnew}" != "$profile" ] || \ | |||
[ "${profile%.rpmsave}" != "$profile" ] || \ | |||
[ "${profile%.orig}" != "$profile" ] || \ | |||
[ "${profile%.rej}" != "$profile" ] || \ | |||
[ "${profile%\~}" != "$profile" ] ; then | |||
return 1 | |||
fi | |||
# Silently ignore the dpkg, pacman, ipk and xbps files | |||
if [ "${profile%.dpkg-new}" != "$profile" ] || \ | |||
[ "${profile%.dpkg-old}" != "$profile" ] || \ | |||
[ "${profile%.dpkg-dist}" != "$profile" ] || \ | |||
[ "${profile%.dpkg-bak}" != "$profile" ] || \ | |||
[ "${profile%.dpkg-remove}" != "$profile" ] || \ | |||
[ "${profile%.ipk}" != "$profile" ] || \ | |||
[ "${profile%.ipk-new}" != "$profile" ] || \ | |||
[ "${profile%.ipk-old}" != "$profile" ] || \ | |||
[ "${profile%.ipk-dist}" != "$profile" ] || \ | |||
[ "${profile%.ipk-bak}" != "$profile" ] || \ | |||
[ "${profile%.ipk-remove}" != "$profile" ] || \ | |||
[ "${profile%.pacsave}" != "$profile" ] || \ | |||
[ "${profile%.pacnew}" != "$profile" ] ; then | |||
return 2 | |||
fi | |||
$(echo "$profile" | grep -E -q '^.+\.new-[0-9\.]+_[0-9]+$'); [ "$?" -eq 0 ] && return 2 | |||
return 0 | |||
} | |||
__parse_profiles_dir() { | |||
local parser_cmd="$1" | |||
local profile_dir="$2" | |||
local status=0 | |||
[ -x "$PARSER" ] || { | |||
log_write err "Unable to execute AppArmor parser" | |||
return 1 | |||
} | |||
[ -d "$profile_dir" ] || { | |||
log_write warning "AppArmor profiles not found: $profile_dir" | |||
return 1 | |||
} | |||
dir_is_empty "$profile_dir"; [ "$?" -eq 0 ] && { | |||
log_write err "No profiles found in $profile_dir" | |||
return 1 | |||
} | |||
local nprocs=$(cat /proc/cpuinfo |grep "processor\t:"|wc -l) | |||
local rc=0 | |||
local xargs_args="" | |||
[ "$nprocs" -ge 2 ] && xargs_args="--max-procs=$nprocs" | |||
"$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir" || { | |||
for profile in "$profile_dir"/*; do | |||
skip_profile "$profile" | |||
skip=$? | |||
[ "$skip" -ne 0 ] && { | |||
[ "$skip" -ne 2 ] && log_write info "Skipped loading profile $profile" | |||
continue | |||
} | |||
[ -f "$profile" ] || continue | |||
echo "$profile" | |||
done | \ | |||
# Use xargs to parallelize calls to the parser over all CPUs | |||
/usr/libexec/xargs-findutils -n1 -d"\n" $xargs_args \ | |||
"$PARSER" $PARSER_OPTS "$parser_cmd" -- | |||
[ "$?" -ne 0 ] && { | |||
rc=1 | |||
log_write err "At least one profile failed to load" | |||
} | |||
} | |||
return $rc | |||
} | |||
parse_profiles() { | |||
case "$1" in | |||
load) | |||
PARSER_CMD="--add" | |||
PARSER_MSG="Loading profiles" | |||
;; | |||
reload) | |||
PARSER_CMD="--replace" | |||
PARSER_MSG="Reloading profiles" | |||
;; | |||
*) | |||
log_write err "Unknown parameter $1" | |||
log_write info "parse_profiles parameter must be either 'load' or 'reload'" | |||
return 1 | |||
;; | |||
esac | |||
log_write info "$PARSER_MSG" | |||
[ -w "$SFS_MOUNTPOINT/.load" ] || { | |||
log_write err "${SFS_MOUNTPOINT}/.load not writable" | |||
return 1 | |||
} | |||
[ -f "$PARSER" ] || { | |||
log_write err "AppArmor parser not found" | |||
return 1 | |||
} | |||
# run parser on all profiles | |||
local rc=0 | |||
for profile_dir in $PROFILE_DIRS; do | |||
__parse_profiles_dir "$PARSER_CMD" "$profile_dir" || rc=$? | |||
done | |||
return $rc | |||
} | |||
is_apparmor_loaded() { | |||
is_securityfs_mounted; [ "$?" -eq 0 ] || { | |||
mount_securityfs | |||
} | |||
[ -f "${SFS_MOUNTPOINT}/profiles" ] && return 0 | |||
[ -d /sys/module/apparmor ] && return 0 || return 1 | |||
} | |||
is_securityfs_mounted() { | |||
[ -d "$SECURITYFS" ] && { | |||
grep -q securityfs /proc/filesystems && grep -q securityfs /proc/mounts | |||
return $? | |||
} | |||
return 1 | |||
} | |||
mount_securityfs() { | |||
local rc=0 | |||
grep -q securityfs /proc/filesystems; [ "$?" -eq 0 ] && { | |||
mount -t securityfs securityfs "$SECURITYFS" | |||
rc=$? | |||
[ "$rc" -eq 0 ] && log_write info "Mounting securityfs" || | |||
log_write err "Failed to mount securityfs" | |||
} | |||
return $rc | |||
} | |||
apparmor_start() { | |||
local announced=0 | |||
is_securityfs_mounted; [ "$?" -ne 0 ] && { | |||
log_write info "Starting AppArmor" | |||
announced=1 | |||
mount_securityfs; [ "$?" -eq 0 ] || return $? | |||
} | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
[ "$announced" -eq 0 ] && log_write info "Starting AppArmor" | |||
announced=1 | |||
log_write err "AppArmor kernel support is not present" | |||
return 1 | |||
} | |||
[ -d /var/lib/apparmor ] || mkdir -p /var/lib/apparmor > /dev/null | |||
is_profiles_loaded; [ "$?" -eq 0 ] || { | |||
[ "$announced" -eq 0 ] && log_write info "Starting AppArmor" | |||
announced=1 | |||
parse_profiles load | |||
return $? | |||
} || { | |||
parse_profiles reload | |||
return $? | |||
} | |||
} | |||
remove_profiles() { | |||
log_write info "Unloading profiles" | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
log_write err "AppArmor kernel support is not present" | |||
return 1 | |||
} | |||
[ -w "$SFS_MOUNTPOINT/.remove" ] || { | |||
log_write err "${SFS_MOUNTPOINT}/.remove not writable" | |||
return 1 | |||
} | |||
[ -x "$PARSER" ] || { | |||
log_write err "Unable to execute AppArmor parser" | |||
return 1 | |||
} | |||
local rc=0 | |||
sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \ | |||
LC_COLLATE=C sort | grep -v // | { | |||
while read -r profile ; do | |||
printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove" | |||
result=$? | |||
[ "$result" -eq 0 ] || rc=$result | |||
done | |||
} | |||
return $rc | |||
} | |||
apparmor_stop() { | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || return 1 | |||
is_profiles_loaded; [ "$?" -eq 0 ] && { | |||
log_write info "Stopping AppArmor" | |||
remove_profiles | |||
return $? | |||
} || return 0 | |||
} | |||
apparmor_restart() { | |||
is_profiles_loaded; [ "$?" -eq 0 ] || { | |||
apparmor_start | |||
return $? | |||
} | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
apparmor_start | |||
return $? | |||
} | |||
log_write info "Restarting AppArmor" | |||
parse_profiles reload | |||
return $? | |||
} | |||
apparmor_reload() { | |||
is_profiles_loaded; [ "$?" -eq 0 ] || { | |||
apparmor_start | |||
return $? | |||
} | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
apparmor_start | |||
return $? | |||
} | |||
log_write info "Reloading AppArmor" | |||
parse_profiles reload | |||
return $? | |||
} | |||
apparmor_list_profiles() { | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
echo "AppArmor kernel support is not present" | |||
return 1 | |||
} | |||
[ -x "$PARSER" ] || { | |||
echo "Unable to execute AppArmor parser" | |||
return 1 | |||
} | |||
# run parser on all profiles | |||
for profile_dir in $PROFILE_DIRS; do | |||
[ -d "$profile_dir" ] || { | |||
echo "AppArmor profiles not found: $profile_dir" | |||
continue | |||
} | |||
for profile in "$profile_dir"/*; do | |||
if skip_profile "$profile" && [ -f "$profile" ] ; then | |||
LIST_ADD=$("$PARSER" -N "$profile" ) | |||
[ "$?" -eq 0 ] && echo "$LIST_ADD" | |||
fi | |||
done | |||
done | |||
return 0 | |||
} | |||
apparmor_status() { | |||
is_apparmor_loaded; [ "$?" -eq 0 ] || { | |||
echo "AppArmor kernel support is not present" | |||
return 1 | |||
} | |||
[ -x "$AA_STATUS" ] && { | |||
"$AA_STATUS" --verbose | |||
return $? | |||
} | |||
echo "AppArmor is enabled." | |||
echo "Install apparmor-utils to receive more detailed status" | |||
echo "information or examine $SFS_MOUNTPOINT directly." | |||
return 0 | |||
} |
@ -0,0 +1,10 @@ | |||
--- /dev/null | |||
+++ b/libraries/libapparmor/Makefile | |||
@@ -0,0 +1,7 @@ | |||
+package=libapparmor | |||
+ | |||
+configure: | |||
+ $(STAGING_DIR_HOST)/bin/aclocal | |||
+ $(STAGING_DIR_HOST)/bin/autoconf --force | |||
+ $(STAGING_DIR_HOST)/bin/libtoolize --automake -c --force | |||
+ $(STAGING_DIR_HOST)/bin/automake -ac |
@ -0,0 +1,11 @@ | |||
--- a/utils/aa-unconfined | |||
+++ b/utils/aa-unconfined | |||
@@ -118,7 +118,7 @@ def read_proc_current(filename): | |||
pids = set() | |||
if paranoid: | |||
pids = get_all_pids() | |||
-elif args.with_ss or (not args.with_netstat and (os.path.exists('/bin/ss') or os.path.exists('/usr/bin/ss'))): | |||
+elif args.with_ss or (not args.with_netstat and (os.path.exists('/usr/sbin/ss') or os.path.exists('/bin/ss') or os.path.exists('/usr/bin/ss') or os.path.exists('/sbin/ss'))): | |||
pids = get_pids_ss() | |||
else: | |||
pids = get_pids_netstat() |
@ -0,0 +1,416 @@ | |||
--- a/utils/aa-notify | |||
+++ b/utils/aa-notify | |||
@@ -13,17 +13,6 @@ | |||
# | |||
# ---------------------------------------------------------------------- | |||
# | |||
-# /etc/apparmor/notify.conf: | |||
-# # set to 'yes' to enable AppArmor DENIED notifications | |||
-# show_notifications="yes" | |||
-# | |||
-# # only people in use_group can run this script | |||
-# use_group="admin" | |||
-# | |||
-# $HOME/.apparmor/notify.conf can have: | |||
-# # set to 'yes' to enable AppArmor DENIED notifications | |||
-# show_notifications="yes" | |||
-# | |||
# In a typical desktop environment one would run as a service the | |||
# command: | |||
# /usr/bin/aa-notify -p -w 10 | |||
@@ -35,7 +24,6 @@ import re | |||
import sys | |||
import time | |||
import struct | |||
-import notify2 | |||
import psutil | |||
import pwd | |||
import grp | |||
@@ -60,56 +48,9 @@ def get_user_login(): | |||
username = os.getlogin() | |||
return username | |||
- | |||
-def get_last_login_timestamp(username): | |||
- '''Directly read wtmp and get last login for user as epoch timestamp''' | |||
- timestamp = 0 | |||
- filename = '/var/log/wtmp' | |||
- last_login = 0 | |||
- | |||
- debug_logger.debug('Username: {}'.format(username)) | |||
- | |||
- with open(filename, "rb") as wtmp_file: | |||
- offset = 0 | |||
- wtmp_filesize = os.path.getsize(filename) | |||
- debug_logger.debug('WTMP filesize: {}'.format(wtmp_filesize)) | |||
- while offset < wtmp_filesize: | |||
- wtmp_file.seek(offset) | |||
- offset += 384 # Increment for next entry | |||
- | |||
- type = struct.unpack("<L", wtmp_file.read(4))[0] | |||
- debug_logger.debug('WTMP entry type: {}'.format(type)) | |||
- | |||
- # Only parse USER lines | |||
- if type == 7: | |||
- # Read each item and move pointer forward | |||
- pid = struct.unpack("<L", wtmp_file.read(4))[0] | |||
- line = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] | |||
- id = wtmp_file.read(4).decode("utf-8", "replace").split('\0', 1)[0] | |||
- user = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] | |||
- host = wtmp_file.read(256).decode("utf-8", "replace").split('\0', 1)[0] | |||
- term = struct.unpack("<H", wtmp_file.read(2))[0] | |||
- exit = struct.unpack("<H", wtmp_file.read(2))[0] | |||
- session = struct.unpack("<L", wtmp_file.read(4))[0] | |||
- timestamp = struct.unpack("<L", wtmp_file.read(4))[0] | |||
- usec = struct.unpack("<L", wtmp_file.read(4))[0] | |||
- entry = (pid, line, id, user, host, term, exit, session, timestamp, usec) | |||
- debug_logger.debug('WTMP entry: {}'.format(entry)) | |||
- | |||
- # Store login timestamp for requested user | |||
- if user == username: | |||
- last_login = timestamp | |||
- | |||
- # When loop is done, last value should be the latest login timestamp | |||
- return last_login | |||
- | |||
- | |||
def format_event(event, logsource): | |||
output = [] | |||
- if 'message_body' in config['']: | |||
- output += [config['']['message_body']] | |||
- | |||
if event.profile: | |||
output += ['Profile: {}'.format(event.profile)] | |||
if event.operation: | |||
@@ -126,7 +67,6 @@ def format_event(event, logsource): | |||
return "\n".join(output) | |||
- | |||
def notify_about_new_entries(logfile, wait=0): | |||
# Kill other instances of aa-notify if already running | |||
for process in psutil.process_iter(): | |||
@@ -154,7 +94,6 @@ def notify_about_new_entries(logfile, wa | |||
# print("parent: %d, child: %d\n" % pids) | |||
os._exit(0) # Exit child without calling exit handlers etc | |||
- | |||
def show_entries_since_epoch(logfile, epoch_since): | |||
count = 0 | |||
for event in get_apparmor_events(logfile, epoch_since): | |||
@@ -172,26 +111,7 @@ def show_entries_since_epoch(logfile, ep | |||
) | |||
if args.verbose: | |||
- if 'message_footer' in config['']: | |||
- print(config['']['message_footer']) | |||
- else: | |||
- print(_('For more information, please see: {}').format(debug_docs_url)) | |||
- | |||
- | |||
-def show_entries_since_last_login(logfile, username=get_user_login()): | |||
- # If running as sudo, use username of sudo user instead of root | |||
- if 'SUDO_USER' in os.environ.keys(): | |||
- username = os.environ['SUDO_USER'] | |||
- | |||
- if args.verbose: | |||
- print(_('Showing entries since {} logged in').format(username)) | |||
- print() # Newline | |||
- epoch_since = get_last_login_timestamp(username) | |||
- if epoch_since == 0: | |||
- print(_('ERROR: Could not find last login'), file=sys.stderr) | |||
- sys.exit(1) | |||
- show_entries_since_epoch(logfile, epoch_since) | |||
- | |||
+ print(_('For more information, please see: {}').format(debug_docs_url)) | |||
def show_entries_since_days(logfile, since_days): | |||
day_in_seconds = 60*60*24 | |||
@@ -199,7 +119,6 @@ def show_entries_since_days(logfile, sin | |||
epoch_since = epoch_now - day_in_seconds * since_days | |||
show_entries_since_epoch(logfile, epoch_since) | |||
- | |||
def follow_apparmor_events(logfile, wait=0): | |||
'''Follow AppArmor events and yield relevant entries until process stops''' | |||
@@ -247,7 +166,6 @@ def follow_apparmor_events(logfile, wait | |||
time.sleep(1) | |||
- | |||
def reopen_logfile_if_needed(logfile, logdata, log_inode, log_size): | |||
retry = True | |||
@@ -279,7 +197,6 @@ def reopen_logfile_if_needed(logfile, lo | |||
return (logdata, log_inode, log_size) | |||
- | |||
def get_apparmor_events(logfile, since=0): | |||
'''Read audit events from log source and yield all relevant events''' | |||
@@ -293,7 +210,6 @@ def get_apparmor_events(logfile, since=0 | |||
except PermissionError: | |||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.".format(logfile))) | |||
- | |||
def parse_logdata(logsource): | |||
'''Traverse any iterable log source and extract relevant AppArmor events''' | |||
@@ -327,53 +243,6 @@ def parse_logdata(logsource): | |||
if event.operation[0:8] != 'profile_': | |||
yield event | |||
- | |||
-def drop_privileges(): | |||
- '''If running as root, drop privileges to USER if known, or fall-back to nobody_user/group''' | |||
- | |||
- if os.geteuid() == 0: | |||
- | |||
- if 'SUDO_USER' in os.environ.keys(): | |||
- next_username = os.environ['SUDO_USER'] | |||
- next_uid = os.environ['SUDO_UID'] | |||
- next_gid = os.environ['SUDO_GID'] | |||
- else: | |||
- nobody_user_info = pwd.getpwnam(nobody_user) | |||
- next_username = nobody_user_info[0] | |||
- next_uid = nobody_user_info[2] | |||
- next_gid = nobody_user_info[3] | |||
- | |||
- debug_logger.debug('Dropping to user "{}" privileges'.format(next_username)) | |||
- | |||
- # @TODO? | |||
- # Remove group privileges, including potential 'adm' group that might | |||
- # have had log read access but also other accesses. | |||
- # os.setgroups([]) | |||
- | |||
- # Try setting the new uid/gid | |||
- # Set gid first, otherwise the latter step would fail on missing permissions | |||
- os.setegid(int(next_gid)) | |||
- os.seteuid(int(next_uid)) | |||
- | |||
-def raise_privileges(): | |||
- '''If was running as user with saved user ID 0, raise back to root privileges''' | |||
- | |||
- if os.geteuid() != 0 and original_effective_user == 0: | |||
- | |||
- debug_logger.debug('Rasing privileges from UID {} back to UID 0 (root)'.format(os.geteuid())) | |||
- | |||
- # os.setgid(int(next_gid)) | |||
- os.seteuid(original_effective_user) | |||
- | |||
-def read_notify_conf(path, shell_config): | |||
- try: | |||
- shell_config.CONF_DIR = path | |||
- conf_dict = shell_config.read_config('notify.conf') | |||
- debug_logger.debug('Found configuration file in {}/notify.conf'.format(shell_config.CONF_DIR)) | |||
- return conf_dict | |||
- except FileNotFoundError: | |||
- return {} | |||
- | |||
def main(): | |||
''' | |||
Main function of aa-notify that parses command line | |||
@@ -381,10 +250,9 @@ def main(): | |||
''' | |||
global _, debug_logger, config, args | |||
- global debug_docs_url, nobody_user, original_effective_user, timeformat | |||
+ global debug_docs_url, original_effective_user, timeformat | |||
debug_docs_url = "https://wiki.ubuntu.com/DebuggingApparmor" | |||
- nobody_user = "nobody" | |||
timeformat = "%c" # Automatically using locale format | |||
original_effective_user = os.geteuid() | |||
@@ -403,180 +271,37 @@ def main(): | |||
debug_logger.debug("Starting aa-notify") | |||
parser = argparse.ArgumentParser(description=_('Display AppArmor notifications or messages for DENIED entries.')) | |||
- parser.add_argument('-p', '--poll', action='store_true', help=_('poll AppArmor logs and display notifications')) | |||
- parser.add_argument('--display', type=str, help=_('set the DISPLAY environment variable (might be needed if sudo resets $DISPLAY)')) | |||
- parser.add_argument('-f', '--file', type=str, help=_('search FILE for AppArmor messages')) | |||
- parser.add_argument('-l', '--since-last', action='store_true', help=_('display stats since last login')) | |||
- parser.add_argument('-s', '--since-days', type=int, metavar=('NUM'), help=_('show stats for last NUM days (can be used alone or with -p)')) | |||
- parser.add_argument('-v', '--verbose', action='store_true', help=_('show messages with stats')) | |||
- parser.add_argument('-u', '--user', type=str, help=_('user to drop privileges to when not using sudo')) | |||
- parser.add_argument('-w', '--wait', type=int, metavar=('NUM'), help=_('wait NUM seconds before displaying notifications (with -p)')) | |||
- parser.add_argument('--debug', action='store_true', help=_('debug mode')) | |||
- parser.add_argument('--configdir', type=str, help=argparse.SUPPRESS) | |||
+ parser.add_argument('-f', '--file', type=str, help=_('Logfile to parse for AppArmor messages')) | |||
+ parser.add_argument('-s', '--since-days', type=int, metavar=('NUM'), help=_('Show stats for last NUM days')) | |||
+ parser.add_argument('-v', '--verbose', action='store_true', help=_('Show messages with stats')) | |||
+ parser.add_argument('--debug', action='store_true', help=_('Debug mode')) | |||
# If a TTY then assume running in test mode and fix output width | |||
if not sys.stdout.isatty(): | |||
parser.formatter_class = lambda prog: argparse.HelpFormatter(prog, width=80) | |||
args = parser.parse_args() | |||
+ args.user = 'root' | |||
# Debug mode can be invoked directly with --debug or env LOGPROF_DEBUG=3 | |||
if args.debug: | |||
debug_logger.activateStderr() | |||
debug_logger.debug('Logging level: {}'.format(debug_logger.debug_level)) | |||
debug_logger.debug('Running as uid: {0[0]}, euid: {0[1]}, suid: {0[2]}'.format(os.getresuid())) | |||
- if args.poll: | |||
- debug_logger.debug('Running with --debug and --poll. Will exit in 100s') | |||
- # Sanity checks | |||
- user_ids = os.getresuid() | |||
- groups_ids = os.getresgid() | |||
- if user_ids[1] != user_ids[2]: | |||
- sys.exit("ERROR: Cannot be started with suid set!") | |||
- if groups_ids[1] != groups_ids[2]: | |||
- sys.exit("ERROR: Cannot be started with sgid set!") | |||
- # Define global variables that will be populated by init_aa() | |||
- # conf = None | |||
logfile = None | |||
- if args.configdir: # prefer --configdir if given | |||
- confdir = args.configdir | |||
- else: # fallback to env variable (or None if not set) | |||
- confdir = os.getenv('__AA_CONFDIR') | |||
- | |||
- aa.init_aa(confdir=confdir) | |||
- | |||
# Initialize aa.logfile | |||
- aa.set_logfile(args.file) | |||
- | |||
- # Load global config reader | |||
- shell_config = aaconfig.Config('shell') | |||
- | |||
- # Load system's notify.conf | |||
- # By default aa.CONFDIR is /etc/apparmor on most production systems | |||
- system_config = read_notify_conf(aa.CONFDIR, shell_config) | |||
- # Set default is no system notify.conf was found | |||
- if not system_config: | |||
- system_config = {'': {'show_notifications': 'yes'}} | |||
- | |||
- # Load user's notify.conf | |||
- if os.path.isfile(os.environ['HOME'] + '/.apparmor/notify.conf'): | |||
- # Use legacy path if the conf file is there | |||
- user_config = read_notify_conf(os.environ['HOME'] + '/.apparmor', shell_config) | |||
- elif 'XDG_CONFIG_HOME' in os.environ and os.path.isfile(os.environ['XDG_CONFIG_HOME'] + '/apparmor/notify.conf'): | |||
- # Use XDG_CONFIG_HOME if it is defined | |||
- user_config = read_notify_conf(os.environ['XDG_CONFIG_HOME'] + '/apparmor', shell_config) | |||
- else: | |||
- # Fallback to the default value of XDG_CONFIG_HOME | |||
- user_config = read_notify_conf(os.environ['HOME'] + '/.config/apparmor', shell_config) | |||
- | |||
- # Merge the two config dicts in an accurate and idiomatic way (requires Python 3.5) | |||
- config = {**system_config, **user_config} | |||
- | |||
- """ | |||
- Possible configuration options: | |||
- - show_notifications | |||
- - message_body | |||
- - message_footer | |||
- - use_group | |||
- """ | |||
- | |||
- # # Config checks | |||
- | |||
- # Warn about unknown keys in the config | |||
- allowed_config_keys = [ | |||
- 'use_group', | |||
- 'show_notifications', | |||
- 'message_body', | |||
- 'message_footer' | |||
- ] | |||
- found_config_keys = config[''].keys() | |||
- unknown_keys = [item for item in found_config_keys if item not in allowed_config_keys] | |||
- for item in unknown_keys: | |||
- print(_('Warning! Configuration item "{}" is unknown!').format(item)) | |||
- | |||
- # Warn if use_group is defined and current group does not match defined | |||
- if 'use_group' in config['']: | |||
- user = pwd.getpwuid(os.geteuid())[0] | |||
- user_groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem] | |||
- gid = pwd.getpwnam(user).pw_gid | |||
- user_groups.append(grp.getgrgid(gid).gr_name) | |||
- | |||
- if config['']['use_group'] not in user_groups: | |||
- print( | |||
- _('ERROR! User {user} not member of {group} group!').format( | |||
- user=user, | |||
- group=config['']['use_group'] | |||
- ), | |||
- file=sys.stderr | |||
- ) | |||
- sys.exit(1) | |||
- # @TODO: Extend UI lib to have warning and error functions that | |||
- # can be used in an uniform way with both text and JSON output. | |||
- | |||
if args.file: | |||
logfile = args.file | |||
- elif os.path.isfile('/var/run/auditd.pid') and os.path.isfile('/var/log/audit/audit.log'): | |||
- # If auditd is running, look at /var/log/audit/audit.log | |||
- logfile = '/var/log/audit/audit.log' | |||
- elif os.path.isfile('/var/log/kern.log'): | |||
- # For aa-notify, the fallback is kern.log, not syslog from aa.logfile | |||
- logfile = '/var/log/kern.log' | |||
+ aa.set_logfile(args.file) | |||
else: | |||
- # If all above failed, use aa cfg | |||
- logfile = aa.logfile | |||
+ logfile = '/var/log/audit/audit.log' | |||
+ aa.set_logfile('/var/log/audit/audit.log') | |||
if args.verbose: | |||
print(_('Using log file'), logfile) | |||
- if args.display: | |||
- os.environ['DISPLAY'] = args.display | |||
- | |||
- if args.poll: | |||
- # Exit immediately if show_notifications is no or any of the options below | |||
- if config['']['show_notifications'] in [False, 'no', 'false', '0']: | |||
- print(_('Showing notifications forbidden in notify.conf, aborting..')) | |||
- sys.exit(0) | |||
- | |||
- # Don't allow usage of aa-notify by root, must be some user. Desktop | |||
- # logins as root are not recommended and certainly not a use case for | |||
- # aa-notify notifications. | |||
- if not args.user and os.getuid() == 0 and 'SUDO_USER' not in os.environ.keys(): | |||
- sys.exit("ERROR: Cannot be started a real root user. Use --user to define what user to use.") | |||
- | |||
- # At this point this script needs to be able to read 'logfile' but once | |||
- # the for loop starts, privileges can be dropped since the file descriptor | |||
- # has been opened and access granted. Further reads of the file will not | |||
- # trigger any new permission checks. | |||
- # @TODO Plan to catch PermissionError here or..? | |||
- for message in notify_about_new_entries(logfile, args.wait): | |||
- | |||
- # Notifications should not be run as root, since root probably is | |||
- # the wrong desktop user and not the one getting the notifications. | |||
- drop_privileges() | |||
- | |||
- # sudo does not preserve DBUS address, so we need to guess it based on UID | |||
- if 'DBUS_SESSION_BUS_ADDRESS' not in os.environ: | |||
- os.environ['DBUS_SESSION_BUS_ADDRESS'] = 'unix:path=/run/user/{}/bus'.format(os.geteuid()) | |||
- | |||
- # Before use, notify2 must be initialized and the DBUS channel | |||
- # should be opened using the non-root user. This this step needs to | |||
- # be executed after the drop_privileges(). | |||
- notify2.init('AppArmor') | |||
- | |||
- n = notify2.Notification( | |||
- _('AppArmor notification'), | |||
- message, | |||
- 'gtk-dialog-warning' | |||
- ) | |||
- n.show() | |||
- | |||
- # When notification is sent, raise privileged back to root if the | |||
- # original effective user id was zero (to be able to read AppArmor logs) | |||
- raise_privileges() | |||
- | |||
- elif args.since_last: | |||
- show_entries_since_last_login(logfile) | |||
elif args.since_days: | |||
show_entries_since_days(logfile, args.since_days) | |||
else: |
@ -0,0 +1,134 @@ | |||
--- a/utils/aa-decode | |||
+++ b/utils/aa-decode | |||
@@ -1,4 +1,4 @@ | |||
-#!/bin/bash | |||
+#!/bin/sh | |||
# | |||
# Copyright (C) 2009-2010, 2012 Canonical Ltd. | |||
# Copyright (C) 2012 Christian Boltz | |||
@@ -16,8 +16,6 @@ | |||
# along with this program; if not, contact Canonical, Ltd. | |||
# | |||
-set -e | |||
- | |||
help() { | |||
cat <<EOM | |||
USAGE: aa-decode [OPTIONS] <encoded string> | |||
@@ -36,13 +34,15 @@ $ cat /var/log/kern.log | aa-decode | |||
EOM | |||
} | |||
-decode() { | |||
- if echo "$1" | egrep -q "^[0-9A-Fa-f]+$" ; then | |||
- python3 -c "import binascii; print(bytes.decode(binascii.unhexlify('$1'), errors='strict'));" | |||
- else | |||
- echo "" | |||
- fi | |||
+match_re() { | |||
+ local result=$(echo "$1" | grep -E "$2" ) | |||
+ [ -z "$result" ] && return 1 || return 0 | |||
+} | |||
+ | |||
+decode() { | |||
+ $(echo "$1" | egrep -q "^[0-9A-Fa-f]+$"); [ "$?" -eq 0 ] && | |||
+ python3 -c "import binascii; print(bytes.decode(binascii.unhexlify('$1'), errors='strict'));" || echo "" | |||
} | |||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then | |||
@@ -51,47 +51,61 @@ if [ "$1" = "-h" ] || [ "$1" = "--help" | |||
fi | |||
# if have an argument, then use it, otherwise process stdin | |||
-if [ -n "$1" ]; then | |||
- e="$1" | |||
- if ! echo "$e" | egrep -q "^[0-9A-Fa-f]+$" ; then | |||
- echo "String should only contain hex characters (0-9, a-f, A-F)" | |||
- exit 1 | |||
- fi | |||
- | |||
- d=`decode $e` | |||
- if [ -z "$d" ]; then | |||
- echo "Could not decode string" | |||
- exit 1 | |||
- fi | |||
+[ -n "$1" ] && { | |||
- echo "Decoded: $d" | |||
- exit 0 | |||
-fi | |||
+ e="$1" | |||
-# For now just look at 'name=...' and 'profile=...', | |||
-# so validate input against this and output based on it. | |||
-# TODO: better handle other cases too | |||
-while read line ; do | |||
+ $(echo "$e" | egrep -q "^[0-9A-Fa-f]+$"); [ "$?" -ne 0 ] && { | |||
+ echo "String should only contain hex characters (0-9, a-f, A-F)" | |||
+ exit 1 | |||
+ } | |||
- # check if line contains encoded name= or profile= | |||
- if [[ "$line" =~ \ (name|profile|proctitle)=[0-9a-fA-F] ]]; then | |||
+ d=$(decode $e) | |||
- # cut the encoded filename/profile name out of the line and decode it | |||
- ne=`echo "$line" | sed 's/.* name=\([^ ]*\).*$/\\1/g'` | |||
- nd="$(decode ${ne/\'/\\\'})" | |||
+ [ -z "$d" ] && { | |||
+ echo "Could not decode string" | |||
+ exit 1 | |||
+ } | |||
- pe=`echo "$line" | sed 's/.* profile=\([^ ]*\).*$/\\1/g'` | |||
- pd="$(decode ${pe/\'/\\\'})" | |||
+ echo "Decoded: $d" | |||
+ exit 0 | |||
+} | |||
- pce=`echo "$line" | sed 's/.* proctitle=\([^ ]*\).*$/\\1/g'` | |||
- pcd="$(decode ${pce/\'/\\\'})" | |||
+[ -t 0 ] && { | |||
+ help | |||
+ exit | |||
+} | |||
+ | |||
+while read line ; do | |||
- # replace encoded name and profile with its decoded counterparts (only if it was encoded) | |||
- test -n "$nd" && line="${line/name=$ne/name=\"$nd\"}" | |||
- test -n "$pd" && line="${line/profile=$pe/profile=\"$pd\"}" | |||
- test -n "$pcd" && line="${line/proctitle=$pce/proctitle=\"$pcd\"}" | |||
+ # check if line contains encoded name= or profile= | |||
- fi | |||
+ matches=0 | |||
+ match_re "$line" "^[[:blank:]](name|profile|proctitle)=[0-9a-fA-F]+"; [ "$?" -eq 0 ] && matches=1 || { | |||
+ match_re "$line" "^(name|profile|proctitle)=[0-9a-fA-F]+"; [ "$?" -eq 0 ] && matches=1 | |||
+ } | |||
+ | |||
+ [ "$matches" -eq 0 ] || { | |||
+ | |||
+ # cut the encoded filename/profile name out of the line and decode it | |||
+ ne=$(echo "$line" | sed 's/.* name=\([^ ]*\).*$/\\1/g') | |||
+ [ "$line" = "$ne" ] && ne=$(echo "$line" | sed 's/.*name=\([^ ]*\).*$/\\1/g') | |||
+ echo var: $ne | |||
+ nd="$(decode ${ne/\'/\\\'})" | |||
+ | |||
+ pe=$(echo "$line" | sed 's/.* profile=\([^ ]*\).*$/\\1/g') | |||
+ [ "$line" = "$pe" ] && pe=$(echo "$line" | sed 's/.*profile=\([^ ]*\).*$/\\1/g') | |||
+ pd="$(decode ${pe/\'/\\\'})" | |||
+ | |||
+ pce=$(echo "$line" | sed 's/.* proctitle=\([^ ]*\).*$/\\1/g') | |||
+ [ "$line" = "$pce" ] && pce=$(echo "$line" | sed 's/.*proctitle=\([^ ]*\).*$/\\1/g') | |||
+ pcd="$(decode ${pce/\'/\\\'})" | |||
+ | |||
+ # replace encoded name and profile with its decoded counterparts (only if it was encoded) | |||
+ test -n "$nd" && line="${line/name=$ne/name=\"$nd\"}" | |||
+ test -n "$pd" && line="${line/profile=$pe/profile=\"$pd\"}" | |||
+ test -n "$pcd" && line="${line/proctitle=$pce/proctitle=\"$pcd\"}" | |||
+ } | |||
echo "$line" | |||
@ -0,0 +1,69 @@ | |||
--- a/binutils/Makefile | |||
+++ b/binutils/Makefile | |||
@@ -107,7 +107,7 @@ docs: manpages | |||
indep: docs | |||
$(Q)$(MAKE) -C po all | |||
-all: arch indep | |||
+all: arch | |||
.PHONY: coverage | |||
coverage: | |||
@@ -147,7 +147,7 @@ tests: $(BINTOOLS) $(SBINTOOLS) $(TESTS) | |||
echo "no tests atm" | |||
.PHONY: install | |||
-install: install-indep install-arch | |||
+install: install-arch | |||
.PHONY: install-arch | |||
install-arch: arch | |||
--- a/parser/Makefile | |||
+++ b/parser/Makefile | |||
@@ -195,7 +195,7 @@ extra_docs: pdf | |||
indep: docs | |||
$(Q)$(MAKE) -C po all | |||
-all: arch indep | |||
+all: arch | |||
.PHONY: coverage | |||
coverage: | |||
@@ -396,7 +396,6 @@ endif | |||
.PHONY: install | |||
install: | |||
- $(MAKE) install-indep | |||
$(MAKE) install-arch | |||
.PHONY: install-arch | |||
--- a/utils/Makefile | |||
+++ b/utils/Makefile | |||
@@ -31,9 +31,7 @@ MANPAGES = ${TOOLS:=.8} logprof.conf.5 | |||
PYFLAKES ?= pyflakes3 | |||
-all: docs | |||
- $(MAKE) -C po all | |||
- $(MAKE) -C vim all | |||
+all: clean | |||
.PHONY: docs | |||
docs: ${MANPAGES} ${HTMLMANPAGES} | |||
@@ -49,15 +47,12 @@ po/${NAME}.pot: ${TOOLS} ${PYMODULES} | |||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${TOOLS} ${PYMODULES}" | |||
.PHONY: install | |||
-install: ${MANPAGES} ${HTMLMANPAGES} | |||
+install: | |||
install -d ${CONFDIR} | |||
install -m 644 logprof.conf severity.db notify.conf ${CONFDIR} | |||
install -d ${BINDIR} | |||
# aa-easyprof is installed by python-tools-setup.py | |||
install -m 755 $(filter-out aa-easyprof, ${TOOLS}) ${BINDIR} | |||
- $(MAKE) -C po install DESTDIR=${DESTDIR} NAME=${NAME} | |||
- $(MAKE) install_manpages DESTDIR=${DESTDIR} | |||
- $(MAKE) -C vim install DESTDIR=${DESTDIR} | |||
${PYTHON} ${PYSETUP} install --prefix=${PYPREFIX} --root=${DESTDIR} --version=${VERSION} | |||
.PHONY: clean |
@ -0,0 +1,190 @@ | |||
--- a/profiles/apparmor.d/usr.sbin.dnsmasq | |||
+++ b/profiles/apparmor.d/usr.sbin.dnsmasq | |||
@@ -1,3 +1,10 @@ | |||
+# Last Modified: Thu Jun 10 01:23:44 2021 | |||
+abi <abi/3.0>, | |||
+ | |||
+include <tunables/global> | |||
+ | |||
+@{TFTP_DIR} = /srv/tftp /srv/tftpboot /var/tftp | |||
+ | |||
# ------------------------------------------------------------------ | |||
# | |||
# Copyright (C) 2009 John Dong <jdong@ubuntu.com> | |||
@@ -9,126 +16,95 @@ | |||
# | |||
# ------------------------------------------------------------------ | |||
-abi <abi/3.0>, | |||
- | |||
-@{TFTP_DIR}=/var/tftp /srv/tftp /srv/tftpboot | |||
-include <tunables/global> | |||
profile dnsmasq /usr/{bin,sbin}/dnsmasq flags=(attach_disconnected) { | |||
include <abstractions/base> | |||
include <abstractions/dbus> | |||
include <abstractions/nameservice> | |||
+ include <abstractions/user-tmp> | |||
+ include if exists <local/usr.sbin.dnsmasq> | |||
capability chown, | |||
+ capability dac_override, | |||
+ capability net_admin, # for DHCP server | |||
capability net_bind_service, | |||
+ capability net_raw, # for DHCP server ping checks | |||
capability setgid, | |||
capability setuid, | |||
- capability dac_override, | |||
- capability net_admin, # for DHCP server | |||
- capability net_raw, # for DHCP server ping checks | |||
+ | |||
network inet raw, | |||
network inet6 raw, | |||
- signal (receive) peer=/usr/{bin,sbin}/libvirtd, | |||
- signal (receive) peer=libvirtd, | |||
- ptrace (readby) peer=/usr/{bin,sbin}/libvirtd, | |||
- ptrace (readby) peer=libvirtd, | |||
+ signal receive peer=/usr/{bin,sbin}/libvirtd, | |||
+ signal receive peer=libvirtd, | |||
- owner /dev/tty rw, | |||
+ ptrace readby peer=/usr/{bin,sbin}/libvirtd, | |||
+ ptrace readby peer=libvirtd, | |||
- @{PROC}/@{pid}/fd/ r, | |||
- | |||
- /etc/dnsmasq.conf r, | |||
- /etc/dnsmasq.d/ r, | |||
- /etc/dnsmasq.d/* r, | |||
- /etc/dnsmasq.d-available/ r, | |||
- /etc/dnsmasq.d-available/* r, | |||
- /etc/ethers r, | |||
- /etc/NetworkManager/dnsmasq.d/ r, | |||
- /etc/NetworkManager/dnsmasq.d/* r, | |||
/etc/NetworkManager/dnsmasq-shared.d/ r, | |||
/etc/NetworkManager/dnsmasq-shared.d/* r, | |||
+ /etc/NetworkManager/dnsmasq.d/ r, | |||
+ /etc/NetworkManager/dnsmasq.d/* r, | |||
/etc/dnsmasq-conf.conf r, | |||
/etc/dnsmasq-resolv.conf r, | |||
- | |||
- /usr/{bin,sbin}/dnsmasq mr, | |||
- | |||
- /var/log/dnsmasq*.log w, | |||
- | |||
+ /etc/dnsmasq.conf r, | |||
+ /etc/dnsmasq.d-available/ r, | |||
+ /etc/dnsmasq.d-available/* r, | |||
+ /etc/dnsmasq.d/ r, | |||
+ /etc/dnsmasq.d/* r, | |||
+ /etc/ethers r, | |||
+ /tmp/** r, | |||
+ /usr/libexec/libvirt_leaseshelper Cx -> libvirt_leaseshelper, | |||
+ /usr/lib{,64}/libvirt/libvirt_leaseshelper Cx -> libvirt_leaseshelper, | |||
/usr/share/dnsmasq{-base,}/ r, | |||
/usr/share/dnsmasq{-base,}/* r, | |||
- | |||
- @{run}/*dnsmasq*.pid w, | |||
- @{run}/dnsmasq-forwarders.conf r, | |||
- @{run}/dnsmasq/ r, | |||
- @{run}/dnsmasq/* rw, | |||
- | |||
+ /usr/{bin,sbin}/dnsmasq mr, | |||
+ /var/lib/NetworkManager/dnsmasq-*.leases rw, | |||
+ /var/lib/libvirt/dnsmasq/ r, | |||
+ /var/lib/libvirt/dnsmasq/* r, | |||
+ /var/lib/lxd-bridge/dnsmasq.*.leases rw, | |||
+ /var/lib/lxd/networks/*/dnsmasq.* r, | |||
+ /var/lib/lxd/networks/*/dnsmasq.leases rw, | |||
+ /var/lib/lxd/networks/*/dnsmasq.pid rw, | |||
+ /var/lib/misc/dnsmasq.*.leases rw, | |||
/var/lib/misc/dnsmasq.leases rw, # Required only for DHCP server usage | |||
- | |||
+ /var/log/dnsmasq*.log w, | |||
/{,usr/}bin/{ba,da,}sh ix, # Required to execute --dhcp-script argument | |||
- | |||
- # access to iface mtu needed for Router Advertisement messages in IPv6 | |||
- # Neighbor Discovery protocol (RFC 2461) | |||
+ @{PROC}/@{pid}/fd/ r, | |||
@{PROC}/sys/net/ipv6/conf/*/mtu r, | |||
- | |||
- # for the read-only TFTP server | |||
@{TFTP_DIR}/ r, | |||
@{TFTP_DIR}/** r, | |||
- | |||
- # libvirt config and hosts file for dnsmasq | |||
- /var/lib/libvirt/dnsmasq/ r, | |||
- /var/lib/libvirt/dnsmasq/* r, | |||
- | |||
- # libvirt pid files for dnsmasq | |||
- @{run}/libvirt/network/ r, | |||
+ @{run}/*dnsmasq*.pid w, | |||
+ @{run}/NetworkManager/NetworkManager.pid w, | |||
+ @{run}/NetworkManager/dnsmasq.conf r, | |||
+ @{run}/NetworkManager/dnsmasq.pid w, | |||
+ @{run}/dnsmasq-forwarders.conf r, | |||
+ @{run}/dnsmasq/ r, | |||
+ @{run}/dnsmasq/* rw, | |||
+ @{run}/libvirt/network/ r, | |||
@{run}/libvirt/network/*.pid rw, | |||
- | |||
- # libvirt lease helper | |||
- /usr/lib{,64}/libvirt/libvirt_leaseshelper Cx -> libvirt_leaseshelper, | |||
- /usr/libexec/libvirt_leaseshelper Cx -> libvirt_leaseshelper, | |||
- | |||
- # lxc-net pid and lease files | |||
- @{run}/lxc/dnsmasq.pid rw, | |||
- /var/lib/misc/dnsmasq.*.leases rw, | |||
- | |||
- # lxd-bridge pid and lease files | |||
- @{run}/lxd-bridge/dnsmasq.pid rw, | |||
- /var/lib/lxd-bridge/dnsmasq.*.leases rw, | |||
- /var/lib/lxd/networks/*/dnsmasq.* r, | |||
- /var/lib/lxd/networks/*/dnsmasq.leases rw, | |||
- /var/lib/lxd/networks/*/dnsmasq.pid rw, | |||
- | |||
- # NetworkManager integration | |||
- /var/lib/NetworkManager/dnsmasq-*.leases rw, | |||
+ @{run}/lxc/dnsmasq.pid rw, | |||
+ @{run}/lxd-bridge/dnsmasq.pid rw, | |||
@{run}/nm-dns-dnsmasq.conf r, | |||
@{run}/nm-dnsmasq-*.pid rw, | |||
@{run}/sendsigs.omit.d/*dnsmasq.pid w, | |||
- @{run}/NetworkManager/dnsmasq.conf r, | |||
- @{run}/NetworkManager/dnsmasq.pid w, | |||
- @{run}/NetworkManager/NetworkManager.pid w, | |||
+ owner /dev/tty rw, | |||
+ | |||
profile libvirt_leaseshelper { | |||
include <abstractions/base> | |||
/etc/libnl-3/classid r, | |||
- | |||
- /usr/lib{,64}/libvirt/libvirt_leaseshelper m, | |||
/usr/libexec/libvirt_leaseshelper m, | |||
- | |||
- owner @{PROC}/@{pid}/net/psched r, | |||
- owner @{PROC}/@{pid}/status r, | |||
- | |||
+ /usr/lib{,64}/libvirt/libvirt_leaseshelper m, | |||
+ /var/lib/libvirt/dnsmasq/*.leases rw, | |||
+ /var/lib/libvirt/dnsmasq/*.status* rw, | |||
+ @{run}/leaseshelper.pid rwk, | |||
@{sys}/devices/system/cpu/ r, | |||
@{sys}/devices/system/node/ r, | |||
@{sys}/devices/system/node/*/meminfo r, | |||
+ owner @{PROC}/@{pid}/net/psched r, | |||
+ owner @{PROC}/@{pid}/status r, | |||
- # libvirt lease and status files for dnsmasq | |||
- /var/lib/libvirt/dnsmasq/*.leases rw, | |||
- /var/lib/libvirt/dnsmasq/*.status* rw, | |||
- | |||
- @{run}/leaseshelper.pid rwk, | |||
} | |||
- | |||
- # Site-specific additions and overrides. See local/README for details. | |||
- include if exists <local/usr.sbin.dnsmasq> | |||
} |