mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-03 07:45:50 +00:00
Compare commits
145 Commits
master
...
v4.1.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
8d9a061a45 | ||
|
94ea0f00b1 | ||
|
99e919c288 | ||
|
d805b5c3f8 | ||
|
2aa7fe4659 | ||
|
c456101ebb | ||
|
9875ba19ef | ||
|
ab15e29654 | ||
|
320a2a5155 | ||
|
00dc6794f5 | ||
|
958a77a2db | ||
|
b4aa2cfde4 | ||
|
86273b746a | ||
|
6a26d1f58c | ||
|
17d3545d07 | ||
|
640c3dde26 | ||
|
380a5c8a72 | ||
|
f26f577742 | ||
|
2700e58755 | ||
|
427a895288 | ||
|
dc0a9dc599 | ||
|
74219b34dc | ||
|
5aaa45e4ce | ||
|
0c02c8afe1 | ||
|
70ed8d6f38 | ||
|
5751614928 | ||
|
73842b54f7 | ||
|
54f1cf8dca | ||
|
2de3b84de2 | ||
|
9fc848be81 | ||
|
fefbf514f7 | ||
|
ae0c588acb | ||
|
0af8c5e26f | ||
|
f4deae6759 | ||
|
0691cfcf3c | ||
|
760ddaeb80 | ||
|
4e46df38cf | ||
|
e9858c0c43 | ||
|
0e59b99623 | ||
|
9a2f0ff702 | ||
|
c153a6916f | ||
|
2316ad42d4 | ||
|
e46ca918a2 | ||
|
610d383de2 | ||
|
5ae6f202f8 | ||
|
d96d69a60c | ||
|
164526d16a | ||
|
5267a7eb14 | ||
|
fd24c230c9 | ||
|
14933dc768 | ||
|
9bf91bbe40 | ||
|
8597b04aac | ||
|
28537ff8ec | ||
|
f90a041921 | ||
|
ae0d1aafda | ||
|
403b3cad10 | ||
|
851f6013f6 | ||
|
0838496c32 | ||
|
191f01b749 | ||
|
788d29aacb | ||
|
1b70d1e9c2 | ||
|
00a5c07db5 | ||
|
6876448a24 | ||
|
297cd44aff | ||
|
32da740f1b | ||
|
b24f0bbfa8 | ||
|
5a4ddbeaeb | ||
|
fd253d1c31 | ||
|
505faeff10 | ||
|
3d5346b48e | ||
|
1d9e28df35 | ||
|
9995e36347 | ||
|
08aeeedc69 | ||
|
d426129baf | ||
|
cda7af8561 | ||
|
f5844dc267 | ||
|
52b83aeac4 | ||
|
89fd37abbf | ||
|
ffff25e21b | ||
|
0e7e509ba8 | ||
|
4722ff8e65 | ||
|
d88c6d3bca | ||
|
37ea52db0c | ||
|
da9c59ab09 | ||
|
8fde25d828 | ||
|
5aa7d046db | ||
|
9c3ac976ec | ||
|
f433acb219 | ||
|
5ee3c03101 | ||
|
6fdc08a5a5 | ||
|
e931449ffc | ||
|
203b4994e9 | ||
|
7b53763f92 | ||
|
ddb33d348c | ||
|
8274bff547 | ||
|
b17750163b | ||
|
9c229d1452 | ||
|
702f2863a4 | ||
|
989bf0b3ed | ||
|
9b1d0ea3d8 | ||
|
a577d92c7b | ||
|
a16aff8e20 | ||
|
4099bf6574 | ||
|
a102e9dc55 | ||
|
7c1eff3867 | ||
|
d69d4d3ddf | ||
|
5c04b791d2 | ||
|
be8d85603e | ||
|
450813869a | ||
|
65c41b7fac | ||
|
d19e5e8990 | ||
|
c11ad3e675 | ||
|
de2bb16ad6 | ||
|
4f1d2ac549 | ||
|
cc9f0ed538 | ||
|
1b8afda407 | ||
|
9aae96356e | ||
|
b5db2361f3 | ||
|
5db4a1e7ca | ||
|
230a975916 | ||
|
aa3592a57e | ||
|
a9aef6f37b | ||
|
c71c486313 | ||
|
4213dcc586 | ||
|
ff7f0ff0ea | ||
|
9da0f6d3db | ||
|
0c1c186267 | ||
|
bfd2a0e014 | ||
|
c87fb0a8c1 | ||
|
05debdb2d8 | ||
|
8b06f61bea | ||
|
34a706f566 | ||
|
a31cbd07aa | ||
|
c4c020cdc0 | ||
|
3c00ed7c85 | ||
|
bf8fd8cfac | ||
|
2ca7d30590 | ||
|
5a39ae82fe | ||
|
c7ce54bcbf | ||
|
2318ba598c | ||
|
3d403fe2a7 | ||
|
9074b20a95 | ||
|
7949339b93 | ||
|
80b6e4ddff | ||
|
d824adcf93 |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
apparmor-*
|
||||
apparmor-
|
||||
cscope.*
|
||||
binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
@@ -7,7 +7,6 @@ binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-load
|
||||
binutils/aa-load.8
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
@@ -121,18 +120,6 @@ libraries/libapparmor/src/tst_aalogmisc
|
||||
libraries/libapparmor/src/tst_aalogmisc.log
|
||||
libraries/libapparmor/src/tst_aalogmisc.o
|
||||
libraries/libapparmor/src/tst_aalogmisc.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.log
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.o
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.log
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.o
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.log
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.o
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.trs
|
||||
libraries/libapparmor/src/tst_features
|
||||
libraries/libapparmor/src/tst_features.log
|
||||
libraries/libapparmor/src/tst_features.o
|
||||
@@ -203,6 +190,7 @@ utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
!utils/emacs/apparmor-mode.el
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
@@ -237,7 +225,6 @@ tests/regression/apparmor/dbus_message
|
||||
tests/regression/apparmor/dbus_service
|
||||
tests/regression/apparmor/dbus_unrequested_reply
|
||||
tests/regression/apparmor/deleted
|
||||
tests/regression/apparmor/disconnected_mount_complain
|
||||
tests/regression/apparmor/env_check
|
||||
tests/regression/apparmor/environ
|
||||
tests/regression/apparmor/exec
|
||||
@@ -250,12 +237,10 @@ tests/regression/apparmor/fchown
|
||||
tests/regression/apparmor/fd_inheritance
|
||||
tests/regression/apparmor/fd_inheritor
|
||||
tests/regression/apparmor/fork
|
||||
tests/regression/apparmor/getcon_verify
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/io_uring
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/linkat_tmpfile
|
||||
tests/regression/apparmor/mkdir
|
||||
tests/regression/apparmor/mmap
|
||||
tests/regression/apparmor/mount
|
||||
|
268
.gitlab-ci.yml
268
.gitlab-ci.yml
@@ -1,51 +1,28 @@
|
||||
spec:
|
||||
inputs:
|
||||
build-test-images:
|
||||
default: false
|
||||
type: boolean
|
||||
description: Explicitly build virtual machine images used by integration tests.
|
||||
---
|
||||
image: ubuntu:latest
|
||||
|
||||
# XXX - add a deploy stage to publish man pages, docs, and coverage
|
||||
# reports
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
- if: $CI_COMMIT_TAG
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- spread
|
||||
|
||||
.ubuntu-common:
|
||||
interruptible: true
|
||||
.ubuntu-before_script:
|
||||
before_script:
|
||||
# Install build-dependencies by loading the package list from the ubuntu/debian cloud-init profile.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_deps "Installing dependencies..."
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- apt-get update -qq
|
||||
- apt-get install --yes yq make lsb-release
|
||||
- |
|
||||
printf 'include .image-garden.mk\n$(info $(UBUNTU_CLOUD_INIT_USER_DATA_TEMPLATE))\n.PHONY: nothing\nnothing:\n' \
|
||||
| make -f - nothing \
|
||||
| yq '.packages | .[]' \
|
||||
| xargs apt-get install --yes --no-install-recommends
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_deps
|
||||
after_script:
|
||||
# Inspect the kernel and lsb-release.
|
||||
- apt-get install --no-install-recommends -y gcc perl liblocale-gettext-perl linux-libc-dev lsb-release make
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
.install-c-build-deps: &install-c-build-deps
|
||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf autoconf-archive automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||
|
||||
build-all:
|
||||
stage: build
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# Run the spread prepare section to build everything.
|
||||
- yq -r '.prepare' <spread.yaml | SPREAD_PATH=. bash -xeu
|
||||
- .ubuntu-before_script
|
||||
artifacts:
|
||||
name: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||
expire_in: 30 days
|
||||
@@ -58,33 +35,39 @@ build-all:
|
||||
- changehat/mod_apparmor/
|
||||
- changehat/pam_apparmor/
|
||||
- profiles/
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
|
||||
- make -C parser
|
||||
- make -C binutils
|
||||
- make -C utils
|
||||
- make -C changehat/mod_apparmor
|
||||
- make -C changehat/pam_apparmor
|
||||
- make -C profiles
|
||||
|
||||
test-libapparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C libraries/libapparmor --touch
|
||||
- *install-c-build-deps
|
||||
- make -C libraries/libapparmor check
|
||||
|
||||
test-parser:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C parser --touch
|
||||
- make -C parser -j $(nproc) tst_binaries
|
||||
- *install-c-build-deps
|
||||
- make -C parser check
|
||||
|
||||
test-binutils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C binutils check
|
||||
|
||||
@@ -92,15 +75,9 @@ test-utils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C utils --touch
|
||||
|
||||
# TODO: move those to cloud-init list?
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter flake8 python3-coverage python3-notify2 python3-psutil python3-setuptools python3-tk python3-ttkthemes python3-gi
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
|
||||
# See apparmor/apparmor#221
|
||||
- make -C parser/tst gen_dbus
|
||||
@@ -116,20 +93,16 @@ test-mod-apparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C changehat/mod_apparmor --touch
|
||||
- make -C changehat/mod_apparmor check
|
||||
|
||||
test-profiles:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C profiles --touch
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-local
|
||||
@@ -138,15 +111,13 @@ shellcheck:
|
||||
stage: test
|
||||
needs: []
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
- shellcheck --version
|
||||
- "./tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
> shellcheck.xml"
|
||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
> shellcheck.xml'
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -168,170 +139,29 @@ variables:
|
||||
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
|
||||
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"
|
||||
|
||||
.send-to-coverity: &send-to-coverity
|
||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@$(ls apparmor-*-cov-int.tar.gz) --form version="$(git describe --tags)"
|
||||
--form description="$(git describe --tags) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||
|
||||
coverity:
|
||||
stage: .post
|
||||
interruptible: true
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
- .ubuntu-before_script
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
- COV_VERSION=$(ls -dt cov-analysis-linux64-* | head -1)
|
||||
- PATH=$PATH:$(pwd)/$COV_VERSION/bin
|
||||
- make coverity
|
||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@$(ls apparmor-*-cov-int.tar.gz) --form version="$(git describe --tags)"
|
||||
--form description="$(git describe --tags) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
|
||||
- *install-c-build-deps
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
- COV_VERSION=$(ls -dt cov-analysis-linux64-* | head -1)
|
||||
- PATH=$PATH:$(pwd)/$COV_VERSION/bin
|
||||
- make coverity
|
||||
- *send-to-coverity
|
||||
artifacts:
|
||||
paths:
|
||||
- "apparmor-*.tar.gz"
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PROJECT_PATH == "apparmor/apparmor"
|
||||
|
||||
.image-garden-x86_64:
|
||||
stage: spread
|
||||
interruptible: true
|
||||
# TODO: use tagged release once container tagging is improved upstream.
|
||||
image: registry.gitlab.com/zygoon/image-garden:latest
|
||||
tags:
|
||||
- linux
|
||||
- x86_64
|
||||
- kvm
|
||||
variables:
|
||||
ARCH: x86_64
|
||||
GARDEN_DL_DIR: dl
|
||||
CACHE_POLICY: pull-push
|
||||
CACHE_COMPRESSION_LEVEL: fastest
|
||||
before_script:
|
||||
# Restore the mtime of the .image-garden.mk file. This helps make determine
|
||||
# if there's actually something to do correctly. Git does not preserve the
|
||||
# mtime of files during checkout.
|
||||
- git restore-mtime .image-garden.mk
|
||||
# Prepare the image in dry-run mode. This helps in debugging cache misses
|
||||
# when files are not cached correctly by the runner, causing the build section
|
||||
# below to always do hevy-duty work.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image_dry_run "Prepare image (dry run)"
|
||||
- image-garden make --dry-run --debug "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image_dry_run
|
||||
script:
|
||||
# Prepare the image, for real.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image "Prepare image"
|
||||
# If there's nothing to do then remove all the files that we would normally
|
||||
# cache so that GitLab skips the cache upload step. This saves significant
|
||||
# time required to re-compress and upload unchanged content.
|
||||
# The idea for how to do is is documented at
|
||||
# https://olex.biz/2025/04/gitlab-ci-prevent-cache-reupload-without-changes/
|
||||
# The GitLab issue requesting a proper feature is
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/226068
|
||||
- |
|
||||
if image-garden make --question "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"; then
|
||||
rm -f "$GARDEN_SYSTEM".* efi-code.*.img efi-vars.*.img
|
||||
rm -rf "$GARDEN_DL_DIR"
|
||||
else
|
||||
image-garden make "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
fi
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image
|
||||
cache:
|
||||
# Cache the base image (pre-customization).
|
||||
- key: image-garden-base-${GARDEN_SYSTEM}.${ARCH}
|
||||
policy: $CACHE_POLICY
|
||||
when: always
|
||||
paths:
|
||||
- $GARDEN_DL_DIR
|
||||
# Those are never mutated so they are safe to share.
|
||||
- efi-code.*.img
|
||||
- efi-vars.*.img
|
||||
# Cache the customized system. This cache depends on .image-garden.mk file
|
||||
# so that any customization updates are immediately acted upon.
|
||||
- key:
|
||||
prefix: image-garden-custom-${GARDEN_SYSTEM}.${ARCH}-
|
||||
files:
|
||||
- .image-garden.mk
|
||||
policy: $CACHE_POLICY
|
||||
when: always
|
||||
paths:
|
||||
- $GARDEN_SYSTEM.*
|
||||
- $GARDEN_SYSTEM.seed.iso
|
||||
- $GARDEN_SYSTEM.meta-data
|
||||
- $GARDEN_SYSTEM.user-data
|
||||
|
||||
# This job builds and caches the image that the job below looks at.
|
||||
image-ubuntu-cloud-24.04-x86_64:
|
||||
extends: .image-garden-x86_64
|
||||
variables:
|
||||
GARDEN_SYSTEM: ubuntu-cloud-24.04
|
||||
needs: []
|
||||
dependencies: []
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
paths:
|
||||
- .image-garden.mk
|
||||
- .gitlab-ci.yml
|
||||
compare_to: "refs/heads/master"
|
||||
- if: $CI_COMMIT_BRANCH && "$[[ inputs.build-test-images ]]" == "true"
|
||||
|
||||
.spread-x86_64:
|
||||
extends: .image-garden-x86_64
|
||||
variables:
|
||||
# GitLab project identifier of zygoon/spread-dist can be seen on
|
||||
# https://gitlab.com/zygoon/spread-dist, under the three-dot menu on
|
||||
# top-right.
|
||||
SPREAD_GITLAB_PROJECT_ID: "65375371"
|
||||
# Git revision of spread to install.
|
||||
# This must have been built via spread-dist.
|
||||
# TODO: switch to upstream 1.0 release when available.
|
||||
SPREAD_REV: 413817eda7bec07a3885e0717c178b965f8924e1
|
||||
# Run all the tasks for a given system.
|
||||
SPREAD_ARGS: "garden:$GARDEN_SYSTEM:"
|
||||
SPREAD_GOARCH: amd64
|
||||
before_script:
|
||||
# Restore the mtime of the .image-garden.mk file. This helps make determine
|
||||
# if there's actually something to do correctly. Git does not preserve the
|
||||
# mtime of files during checkout.
|
||||
- git restore-mtime .image-garden.mk
|
||||
# Prepare the image in dry-run mode. This helps in debugging cache misses
|
||||
# when files are not cached correctly by the runner, causing the build section
|
||||
# below to always do hevy-duty work.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image_dry_run "Prepare image (dry run)"
|
||||
- image-garden make --dry-run --debug "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
- stat .image-garden.mk "$GARDEN_SYSTEM".* || true
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image_dry_run
|
||||
# Install the selected revision of spread.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_spread "Installing spread..."
|
||||
# Install pre-built spread from https://gitlab.com/zygoon/spread-dist generic package repository.
|
||||
- |
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --location --output spread "${CI_API_V4_URL}/projects/${SPREAD_GITLAB_PROJECT_ID}/packages/generic/spread/${SPREAD_REV}/spread.${SPREAD_GOARCH}"
|
||||
- chmod +x spread
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_spread
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K%s\n' section_start "$(date +%s)" run_spread "Running spread for $GARDEN_SYSTEM..."
|
||||
# TODO: transform to inject ^...$ to properly select jobs to run.
|
||||
- mkdir -p spread-logs spread-artifacts
|
||||
- ./spread -list $SPREAD_ARGS |
|
||||
split --number=l/"${CI_NODE_INDEX:-1}"/"${CI_NODE_TOTAL:-1}" |
|
||||
xargs --verbose ./spread -v -artifacts ./spread-artifacts -v | tee spread-logs/"$GARDEN_SYSTEM".log
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" run_spread
|
||||
artifacts:
|
||||
paths:
|
||||
- spread-logs
|
||||
- spread-artifacts
|
||||
when: always
|
||||
|
||||
spread-ubuntu-cloud-24.04-x86_64:
|
||||
extends: .spread-x86_64
|
||||
variables:
|
||||
GARDEN_SYSTEM: ubuntu-cloud-24.04
|
||||
SPREAD_ARGS: garden:$GARDEN_SYSTEM:tests/regression/ garden:$GARDEN_SYSTEM:tests/profiles/
|
||||
CACHE_POLICY: pull
|
||||
dependencies: []
|
||||
needs:
|
||||
- job: image-ubuntu-cloud-24.04-x86_64
|
||||
optional: true
|
||||
parallel: 4
|
||||
|
@@ -2,18 +2,12 @@
|
||||
# All the package installation happens through cloud-init profiles defined
|
||||
# below.
|
||||
|
||||
# NOTE: Should the kernel be out of date, just increment this value. Make will
|
||||
# re-create the image whenever the .image-garden.mk file is more recent than
|
||||
# the image itself. In reality all you need is touch(1), but this is more apt.
|
||||
unused=1
|
||||
|
||||
# This is the cloud-init user-data profile for all Debian systems. Note that it
|
||||
# is an extension of the default profile necessary for operation of
|
||||
# image-garden.
|
||||
define DEBIAN_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
packages:
|
||||
- apache2-dev
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
@@ -21,18 +15,13 @@ packages:
|
||||
- bison
|
||||
- build-essential
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flake8
|
||||
- flex
|
||||
- fuse-overlayfs
|
||||
- gdb
|
||||
- gettext
|
||||
- libdbus-1-dev
|
||||
- libpam0g-dev
|
||||
- libtool
|
||||
- liburing-dev
|
||||
- pkg-config
|
||||
- proftpd-core
|
||||
- python3-all-dev
|
||||
- python3-gi
|
||||
- python3-notify2
|
||||
@@ -41,13 +30,6 @@ packages:
|
||||
- python3-tk
|
||||
- python3-ttkthemes
|
||||
- swig
|
||||
- tinyproxy
|
||||
# Update all the packages. This allows us to be on the up-to-date kernel
|
||||
# version that we cannot otherwise easily select with cloud init alone. Note
|
||||
# that we do not need to reboot the system as image garden shuts down the image
|
||||
# after first boot. On subsequent boot we will be running the latest kernel.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
||||
|
||||
# Ubuntu shares cloud-init profile with Debian.
|
||||
@@ -56,10 +38,7 @@ UBUNTU_CLOUD_INIT_USER_DATA_TEMPLATE=$(DEBIAN_CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
# This is the cloud-init user-data profile for openSUSE Tumbleweed.
|
||||
define OPENSUSE_tumbleweed_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
- sed -i -e 's/security=selinux/security=apparmor/g' /etc/default/grub
|
||||
- update-bootloader
|
||||
packages:
|
||||
- apache2-devel
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
@@ -67,20 +46,15 @@ packages:
|
||||
- bison
|
||||
- dbus-1-devel
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flex
|
||||
- fuse-overlayfs
|
||||
- gcc
|
||||
- gcc-c++
|
||||
- gdb
|
||||
- gettext
|
||||
- gobject-introspection
|
||||
- libtool
|
||||
- liburing2-devel
|
||||
- make
|
||||
- pam-devel
|
||||
- pkg-config
|
||||
- python3-devel
|
||||
- python3-flake8
|
||||
- python3-notify2
|
||||
- python3-psutil
|
||||
@@ -88,42 +62,7 @@ packages:
|
||||
- python3-setuptools
|
||||
- python3-tk
|
||||
- python311
|
||||
- python3-devel
|
||||
- python311-devel
|
||||
- swig
|
||||
- which
|
||||
# See above for rationale.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
||||
|
||||
define FEDORA_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
packages:
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
- automake
|
||||
- bison
|
||||
- dbus-devel
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flex
|
||||
- gdb
|
||||
- gettext
|
||||
- httpd-devel
|
||||
- libstdc++-static
|
||||
- libtool
|
||||
- liburing-devel
|
||||
- pam-devel
|
||||
- perl
|
||||
- pkg-config
|
||||
- python3-devel
|
||||
- python3-flake8
|
||||
- python3-gobject-base
|
||||
- python3-notify2
|
||||
- python3-tkinter
|
||||
- swig
|
||||
# See above for rationale.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
||||
|
5
Makefile
5
Makefile
@@ -54,9 +54,12 @@ snapshot: clean
|
||||
.PHONY: coverity
|
||||
coverity: snapshot
|
||||
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
|
||||
$(foreach dir, libraries/libapparmor utils, \
|
||||
cov-build --dir $(COVERITY_DIR) --no-command --fs-capture-search $(SNAPSHOT_NAME)/$(dir); \
|
||||
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-python-$(subst /,.,$(dir)).txt ;)
|
||||
cov-build --dir $(COVERITY_DIR) -- sh -c \
|
||||
"$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
$(MAKE) -j $$(nproc) -C $(SNAPSHOT_NAME)/$(dir);) "
|
||||
$(MAKE) -C $(SNAPSHOT_NAME)/$(dir);) "
|
||||
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
|
||||
|
||||
.PHONY: export_dir
|
||||
|
43
README.md
43
README.md
@@ -111,21 +111,13 @@ $ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
Note that, in general, the build steps can be run in parallel, while the test
|
||||
steps do not gain much speedup from being run in parallel. This is because the
|
||||
test steps spawn a handful of long-lived test runner processes that mostly
|
||||
run their tests sequentially and do not use `make`'s jobserver. Moreover,
|
||||
process spawning overhead constitutes a significant part of test runtime, so
|
||||
reworking the test harnesses to add parallelism (which would be a major undertaking
|
||||
for the harnesses that do not have it already) would not produce much of a speedup.
|
||||
|
||||
### libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
$ sh ./autogen.sh
|
||||
$ sh ./configure --prefix=/usr --with-perl --with-python # see below
|
||||
$ make -j $(nproc)
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
@@ -138,7 +130,7 @@ generate Ruby bindings to libapparmor.]
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
$ make -j $(nproc)
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
@@ -147,8 +139,7 @@ $ make install
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make -j $(nproc) tst_binaries # a build step of make check that can be parallelized
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
@@ -158,7 +149,7 @@ $ make install
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make -j $(nproc)
|
||||
$ make
|
||||
$ make check PYFLAKES=/usr/bin/pyflakes3
|
||||
$ make install
|
||||
```
|
||||
@@ -167,7 +158,7 @@ $ make install
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
@@ -176,7 +167,7 @@ $ make install
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
@@ -214,18 +205,6 @@ in an ephemeral virtual machine. This allows testing in isolation from the
|
||||
host, as well as testing across different commonly used distributions and their
|
||||
real kernels.
|
||||
|
||||
Image Garden is available as a snap. If you wish to use it this way then snap
|
||||
then install the snap with:
|
||||
|
||||
```sh
|
||||
sudo snap install image-garden
|
||||
```
|
||||
|
||||
If you need to install snapd first, see https://snapcraft.io/docs/installing-snapd
|
||||
|
||||
Alternatively you may build image-garden and spread from source, and install
|
||||
dependencies manually.
|
||||
|
||||
```sh
|
||||
sudo apt install git golang whois ovmf genisoimage qemu-utils qemu-system
|
||||
go install github.com/snapcore/spread/cmd/spread@latest
|
||||
@@ -239,9 +218,8 @@ git clean -xdf
|
||||
# or ~/go/bin/spread -v garden:ubuntu-cloud-24.04:tests/regression/apparmor:at_secure
|
||||
```
|
||||
|
||||
Running the `run_spread.sh` script, with `image-garden` snap installed or with
|
||||
`spread` on `PATH` will run all the tests across several supported systems
|
||||
(Debian, Ubuntu and openSUSE).
|
||||
Running the `run_spread.sh` script, with `spread` on `PATH` will run all the
|
||||
tests across several supported systems (Debian, Ubuntu and openSUSE).
|
||||
|
||||
If you include a `bzImage` file in the root of the repository then that kernel
|
||||
will be used in the integration test. Please look at `spread.yaml` for details.
|
||||
@@ -256,7 +234,7 @@ To run:
|
||||
### Regression tests - using apparmor userspace installed on host
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make -j $(nproc) USE_SYSTEM=1
|
||||
$ make USE_SYSTEM=1
|
||||
$ sudo make tests USE_SYSTEM=1
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
@@ -269,7 +247,7 @@ $ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make -j $(nproc)
|
||||
$ make
|
||||
$ sudo make tests
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
@@ -403,7 +381,6 @@ The aa-notify tool's Python dependencies can be satisfied by installing the
|
||||
following packages (Debian package names, other distros may vary):
|
||||
* python3-notify2
|
||||
* python3-psutil
|
||||
* python3-sqlite (part of the python3.NN-stdlib package)
|
||||
* python3-tk
|
||||
* python3-ttkthemes
|
||||
* python3-gi
|
||||
|
@@ -21,7 +21,7 @@ DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/bin
|
||||
SBINDIR=${DESTDIR}/usr/sbin
|
||||
LOCALEDIR=/usr/share/locale
|
||||
MANPAGES=aa-enabled.1 aa-exec.1 aa-features-abi.1 aa-load.8 aa-status.8
|
||||
MANPAGES=aa-enabled.1 aa-exec.1 aa-features-abi.1 aa-status.8
|
||||
|
||||
WARNINGS = -Wall
|
||||
CPP_WARNINGS =
|
||||
|
@@ -80,109 +80,6 @@ aa-exec.
|
||||
|
||||
=back
|
||||
|
||||
=head1 RESTRICTIONS
|
||||
|
||||
aa-exec uses I<aa_change_profile(3)> to change application confinement.
|
||||
The use of I<aa_change_profile(3)> may be restricted by policy in ways
|
||||
that will cause failure or results different than expected.
|
||||
|
||||
Even when using I<aa-exec> from unconfined restrictions in policy can
|
||||
causes failure or the confinement entered to be different than requested
|
||||
|
||||
See the unpriviled unconfined restriction documentation for more detail.
|
||||
https://gitlab.com/apparmor/apparmor/-/wikis/unprivileged_unconfined_restriction
|
||||
|
||||
=head1 STACKING
|
||||
|
||||
aa-exec can be used to setup a stack of profiles as confinement. When an
|
||||
application is confined by a stack, all profiles in the stack are checked
|
||||
as if they were the profile confining the application. The resulting
|
||||
mediation is the intersection of what is allowed by each profile in the
|
||||
stack.
|
||||
|
||||
The profiles in a stack are treated independently. Each profile can have
|
||||
its own flags and profile transitions. During an exec each profile gets
|
||||
to specify its transition and the results brought together to form a
|
||||
new canonicalized stack.
|
||||
|
||||
The profile separator indicating a stack is the character sequence I<//&>.
|
||||
Thus a stack can be expressed using
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p "unconfined//&firefox" -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
unconfined 30714 pts/12 00:00:00 bash
|
||||
firefox//&unconfined (unconfined) 31160 pts/12 00:00:00 bash
|
||||
firefox//&unconfined (unconfined) 31171 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
=head1 NAMESPACES
|
||||
|
||||
aa-exec can be used to enter confinement in another policy namespace
|
||||
if the policy namespaces exists, is visible, and the profile exists in
|
||||
the namespace. Note applications launched within the namespace will
|
||||
not be able to exit the namespace, and may be restricted by additional
|
||||
confinement around namespacing. Files and resources visible to the
|
||||
parent that launches the application may not be visible in the policy
|
||||
namespace resulting in access denials.
|
||||
|
||||
To enter a policy namespace the profile is prefixed with the namespace's
|
||||
name, using a I<:> prefix and suffix.
|
||||
|
||||
Eg.
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p :ex1:unconfined -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
- 30714 pts/12 00:00:00 bash
|
||||
unconfined 34372 pts/12 00:00:00 bash
|
||||
unconfined 34379 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
Confinement of processes outside of the namespace may not be visible
|
||||
in which case the confinement will be represented with a -. If policy
|
||||
is stacked only part of the confinement might be visible. However
|
||||
confinement is usually fully visible from the parent policy namespace.
|
||||
|
||||
Eg. the confinement of the child can be queried in the parent to see
|
||||
|
||||
=over 4
|
||||
|
||||
$ ps -Z 34372
|
||||
LABEL PID TTY STAT TIME COMMAND
|
||||
:ex1:unconfined 34372 pts/12 S+ 0:00 bash
|
||||
|
||||
=back
|
||||
|
||||
And in the case of stacking with namespaces
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p "unconfined//&:ex1:unconfined" -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
- 30714 pts/12 00:00:00 bash
|
||||
unconfined 36298 pts/12 00:00:00 bash
|
||||
unconfined 36305 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
while from the parent namespace the full confinement can be seen
|
||||
|
||||
=over 4
|
||||
|
||||
$ ps -Z 36298
|
||||
LABEL PID TTY STAT TIME COMMAND
|
||||
unconfined//&:ex1:unconfined 36298 pts/12 S+ 0:00 bash
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
@@ -190,7 +87,7 @@ L<https://gitlab.com/apparmor/apparmor/-/issues>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_change_profile(3),
|
||||
aa-stack(8), aa-namespace(8), apparmor(7), apparmor.d(5), aa_change_profile(3),
|
||||
aa_change_onexec(3) and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -1,77 +0,0 @@
|
||||
# This publication is intellectual property of Canonical Ltd. Its contents
|
||||
# can be duplicated, either in part or in whole, provided that a copyright
|
||||
# label is visibly located on each copy.
|
||||
#
|
||||
# All information found in this book has been compiled with utmost
|
||||
# attention to detail. However, this does not guarantee complete accuracy.
|
||||
# Neither Canonical Ltd, the authors, nor the translators shall be held
|
||||
# liable for possible errors or the consequences thereof.
|
||||
#
|
||||
# Many of the software and hardware descriptions cited in this book
|
||||
# are registered trademarks. All trade names are subject to copyright
|
||||
# restrictions and may be registered trade marks. Canonical Ltd
|
||||
# essentially adheres to the manufacturer's spelling.
|
||||
#
|
||||
# Names of products and trademarks appearing in this book (with or without
|
||||
# specific notation) are likewise subject to trademark and trade protection
|
||||
# laws and may thus fall under copyright restrictions.
|
||||
#
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-load - load precompiled AppArmor policy from cache location(s)
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-load> [options] (cache file|cache dir|cache base dir)+
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-load> loads precompiled AppArmor policy from the specified locations.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-load> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -f, --force
|
||||
|
||||
Force B<aa-load> to load a policy even if its abi does not match the kernel abi.
|
||||
|
||||
=item -d, --debug
|
||||
|
||||
Display debug messages.
|
||||
|
||||
=item -v, --verbose
|
||||
|
||||
Display progress and error messages.
|
||||
|
||||
=item -n, --dry-run
|
||||
|
||||
Do not actually load the specified policy/policies into the kernel.
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
|
||||
Upon exiting, B<aa-load> returns 0 upon success and 1 upon an error loading
|
||||
the precompiled policy.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
@@ -117,13 +117,13 @@ display only counts for selected information.
|
||||
=item --filter.mode=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processes and profiles apparmor profile
|
||||
applied against the displayed processess and profiles apparmor profile
|
||||
mode, reducing the output.
|
||||
|
||||
=item --filter.profiles=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processes and profiles confining
|
||||
applied against the displayed processess and profiles confining
|
||||
profile, reducing the output.
|
||||
|
||||
=item --filter.pid=filter
|
||||
|
@@ -17,7 +17,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -310,8 +309,9 @@ static int load_arg(char *arg)
|
||||
|
||||
static void print_usage(const char *command)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] (cache file|cache dir|cache base dir)+\n"
|
||||
"Load precompiled AppArmor policy from cache location(s)\n\n"
|
||||
printf("Usage: %s [OPTIONS] (cache file|cache dir|cache base dir)]*\n"
|
||||
"Load Precompiled AppArmor policy from a cache location or \n"
|
||||
"locations.\n\n"
|
||||
"Options:\n"
|
||||
" -f, --force load policy even if abi does not match the kernel\n"
|
||||
" -d, --debug display debug messages\n"
|
||||
|
@@ -20,8 +20,6 @@
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <regex.h>
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/apparmor_private.h>
|
||||
@@ -133,7 +131,7 @@ const char *process_statuses[] = {"enforce", "complain", "prompt", "kill", "unco
|
||||
#define eprintf(...) \
|
||||
do { \
|
||||
if (!quiet) \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define dprintf(...) \
|
||||
@@ -158,14 +156,14 @@ static int open_profiles(FILE **fp)
|
||||
|
||||
ret = stat("/sys/module/apparmor", &st);
|
||||
if (ret != 0) {
|
||||
eprintf(_("apparmor not present.\n"));
|
||||
eprintf("apparmor not present.\n");
|
||||
return AA_EXIT_DISABLED;
|
||||
}
|
||||
dprintf(_("apparmor module is loaded.\n"));
|
||||
dprintf("apparmor module is loaded.\n");
|
||||
|
||||
ret = aa_find_mountpoint(&apparmorfs);
|
||||
if (ret == -1) {
|
||||
eprintf(_("apparmor filesystem is not mounted.\n"));
|
||||
eprintf("apparmor filesystem is not mounted.\n");
|
||||
return AA_EXIT_NO_CONTROL;
|
||||
}
|
||||
|
||||
@@ -178,9 +176,9 @@ static int open_profiles(FILE **fp)
|
||||
*fp = fopen(apparmor_profiles, "r");
|
||||
if (*fp == NULL) {
|
||||
if (errno == EACCES) {
|
||||
eprintf(_("You do not have enough privilege to read the profile set.\n"));
|
||||
eprintf("You do not have enough privilege to read the profile set.\n");
|
||||
} else {
|
||||
eprintf(_("Could not open %s: %s"), apparmor_profiles, strerror(errno));
|
||||
eprintf("Could not open %s: %s", apparmor_profiles, strerror(errno));
|
||||
}
|
||||
return AA_EXIT_NO_PERM;
|
||||
}
|
||||
@@ -353,7 +351,7 @@ static int get_processes(struct profile *profiles,
|
||||
continue;
|
||||
} else if (rc == -1 ||
|
||||
asprintf(&exe, "/proc/%s/exe", entry->d_name) == -1) {
|
||||
eprintf(_("ERROR: Failed to allocate memory\n"));
|
||||
eprintf("ERROR: Failed to allocate memory\n");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
} else if (mode) {
|
||||
@@ -376,7 +374,7 @@ static int get_processes(struct profile *profiles,
|
||||
// ensure enough space for NUL terminator
|
||||
real_exe = calloc(PATH_MAX + 1, sizeof(char));
|
||||
if (real_exe == NULL) {
|
||||
eprintf(_("ERROR: Failed to allocate memory\n"));
|
||||
eprintf("ERROR: Failed to allocate memory\n");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
@@ -600,7 +598,7 @@ static int detailed_profiles(FILE *outf, filters_t *filters, bool json,
|
||||
*/
|
||||
subfilters.mode = &mode_filter;
|
||||
if (regcomp(&mode_filter, profile_statuses[i], REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile sub filter '%s'\n"),
|
||||
eprintf("Error: failed to compile sub filter '%s'\n",
|
||||
profile_statuses[i]);
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
@@ -666,7 +664,7 @@ static int detailed_processes(FILE *outf, filters_t *filters, bool json,
|
||||
*/
|
||||
subfilters.mode = &mode_filter;
|
||||
if (regcomp(&mode_filter, process_statuses[i], REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile sub filter '%s'\n"),
|
||||
eprintf("Error: failed to compile sub filter '%s'\n",
|
||||
profile_statuses[i]);
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
@@ -728,7 +726,7 @@ exit:
|
||||
|
||||
static int print_legacy(const char *command)
|
||||
{
|
||||
printf(_("Usage: %s [OPTIONS]\n"
|
||||
printf("Usage: %s [OPTIONS]\n"
|
||||
"Legacy options and their equivalent command\n"
|
||||
" --profiled --count --profiles\n"
|
||||
" --enforced --count --profiles --mode=enforced\n"
|
||||
@@ -736,8 +734,8 @@ static int print_legacy(const char *command)
|
||||
" --kill --count --profiles --mode=kill\n"
|
||||
" --prompt --count --profiles --mode=prompt\n"
|
||||
" --special-unconfined --count --profiles --mode=unconfined\n"
|
||||
" --process-mixed --count --ps --mode=mixed\n"),
|
||||
command);
|
||||
" --process-mixed --count --ps --mode=mixed\n",
|
||||
command);
|
||||
|
||||
exit(0);
|
||||
return 0;
|
||||
@@ -747,7 +745,7 @@ static int usage_filters(void)
|
||||
{
|
||||
long unsigned int i;
|
||||
|
||||
printf(_("Usage of filters\n"
|
||||
printf("Usage of filters\n"
|
||||
"Filters are used to reduce the output of information to only\n"
|
||||
"those entries that will match the filter. Filters use posix\n"
|
||||
"regular expression syntax. The possible values for exes that\n"
|
||||
@@ -757,7 +755,7 @@ static int usage_filters(void)
|
||||
" --filter.profiles: regular expression to match displayed profile names\n"
|
||||
" --filter.pid: regular expression to match displayed processes pids\n"
|
||||
" --filter.exe: regular expression to match executable\n"
|
||||
));
|
||||
);
|
||||
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
|
||||
printf("%s%s", i ? ", " : "", process_statuses[i]);
|
||||
}
|
||||
@@ -775,7 +773,7 @@ static int print_usage(const char *command, bool error)
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf(_("Usage: %s [OPTIONS]\n"
|
||||
printf("Usage: %s [OPTIONS]\n"
|
||||
"Displays various information about the currently loaded AppArmor policy.\n"
|
||||
"Default if no options given\n"
|
||||
" --show=all\n\n"
|
||||
@@ -792,8 +790,8 @@ static int print_usage(const char *command, bool error)
|
||||
" --verbose (default) displays data points about loaded policy set\n"
|
||||
" --quiet don't output error messages\n"
|
||||
" -h[(legacy|filters)] this message, or info on the specified option\n"
|
||||
" --help[=(legacy|filters)] this message, or info on the specified option\n"),
|
||||
command);
|
||||
" --help[=(legacy|filters)] this message, or info on the specified option\n",
|
||||
command);
|
||||
|
||||
exit(status);
|
||||
|
||||
@@ -869,7 +867,7 @@ static int parse_args(int argc, char **argv)
|
||||
} else if (strcmp(optarg, "filters") == 0) {
|
||||
usage_filters();
|
||||
} else {
|
||||
eprintf(_("Error: Invalid --help option '%s'.\n"), optarg);
|
||||
eprintf("Error: Invalid --help option '%s'.\n", optarg);
|
||||
print_usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
@@ -937,7 +935,7 @@ static int parse_args(int argc, char **argv)
|
||||
} else if (strcmp(optarg, "processes") == 0) {
|
||||
opt_show = SHOW_PROCESSES;
|
||||
} else {
|
||||
eprintf(_("Error: Invalid --show option '%s'.\n"), optarg);
|
||||
eprintf("Error: Invalid --show option '%s'.\n", optarg);
|
||||
print_usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
@@ -959,7 +957,7 @@ static int parse_args(int argc, char **argv)
|
||||
break;
|
||||
|
||||
default:
|
||||
eprintf(_("Error: Invalid command.\n"));
|
||||
eprintf("Error: Invalid command.\n");
|
||||
print_usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
@@ -984,7 +982,7 @@ int main(int argc, char **argv)
|
||||
if (argc > 1) {
|
||||
int pos = parse_args(argc, argv);
|
||||
if (pos < argc) {
|
||||
eprintf(_("Error: Unknown options.\n"));
|
||||
eprintf("Error: Unknown options.\n");
|
||||
print_usage(progname, true);
|
||||
}
|
||||
} else {
|
||||
@@ -996,24 +994,24 @@ int main(int argc, char **argv)
|
||||
|
||||
init_filters(&filters, &filter_set);
|
||||
if (regcomp(filters.mode, opt_mode, REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile mode filter '%s'\n"),
|
||||
eprintf("Error: failed to compile mode filter '%s'\n",
|
||||
opt_mode);
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
if (regcomp(filters.profile, opt_profiles, REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile profiles filter '%s'\n"),
|
||||
eprintf("Error: failed to compile profiles filter '%s'\n",
|
||||
opt_profiles);
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if (regcomp(filters.pid, opt_pid, REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile ps filter '%s'\n"),
|
||||
eprintf("Error: failed to compile ps filter '%s'\n",
|
||||
opt_pid);
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if (regcomp(filters.exe, opt_exe, REG_NOSUB) != 0) {
|
||||
eprintf(_("Error: failed to compile exe filter '%s'\n"),
|
||||
eprintf("Error: failed to compile exe filter '%s'\n",
|
||||
opt_exe);
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto out;
|
||||
@@ -1028,7 +1026,7 @@ int main(int argc, char **argv)
|
||||
outf_save = outf;
|
||||
outf = open_memstream(&buffer, &buffer_size);
|
||||
if (!outf) {
|
||||
eprintf(_("Failed to open memstream: %m\n"));
|
||||
eprintf("Failed to open memstream: %m\n");
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1038,10 +1036,8 @@ int main(int argc, char **argv)
|
||||
* have policy associated.
|
||||
*/
|
||||
ret = get_profiles(fp, &profiles, &nprofiles);
|
||||
if (ret == AA_EXIT_NO_POLICY) {
|
||||
eprintf(_("No policy loaded into the kernel\n"));
|
||||
} else if (ret != 0 && !opt_json) {
|
||||
eprintf(_("Failed to retrieve profiles from kernel: %d....\n"), ret);
|
||||
if (ret != 0) {
|
||||
eprintf("Failed to get profiles: %d....\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1070,7 +1066,7 @@ int main(int argc, char **argv)
|
||||
|
||||
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
||||
if (ret != 0) {
|
||||
eprintf(_("Failed to get confinement information from processes: %d....\n"), ret);
|
||||
eprintf("Failed to get processes: %d....\n", ret);
|
||||
} else if (opt_count) {
|
||||
ret = simple_filtered_process_count(outf, &filters, opt_json,
|
||||
processes, nprocesses);
|
||||
@@ -1096,14 +1092,14 @@ int main(int argc, char **argv)
|
||||
outf = outf_save;
|
||||
json = cJSON_Parse(buffer);
|
||||
if (!json) {
|
||||
eprintf(_("Failed to parse json output"));
|
||||
eprintf("Failed to parse json output");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pretty = cJSON_Print(json);
|
||||
if (!pretty) {
|
||||
eprintf(_("Failed to print pretty json"));
|
||||
eprintf("Failed to print pretty json");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
# Translations for aa_enabled
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -1,14 +1,14 @@
|
||||
# Translations for aa_exec
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -1,14 +1,14 @@
|
||||
# Translations for aa_features_abi
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2011.
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -1,34 +0,0 @@
|
||||
# Translations for aa_load
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_load.c:40
|
||||
msgid "aa-load: WARN: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:41
|
||||
msgid "aa-load: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:51
|
||||
msgid "\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:52
|
||||
msgid "aa-load: DEBUG: "
|
||||
msgstr ""
|
@@ -1,179 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2025-04-26 11:12-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_status.c:161
|
||||
msgid "apparmor not present.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:164
|
||||
msgid "apparmor module is loaded.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:168
|
||||
msgid "apparmor filesystem is not mounted.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:181
|
||||
msgid "You do not have enough privilege to read the profile set.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:183
|
||||
#, c-format
|
||||
msgid "Could not open %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:356 ../aa_status.c:379
|
||||
msgid "ERROR: Failed to allocate memory\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:587 ../aa_status.c:653 ../aa_status.c:603 ../aa_status.c:669
|
||||
#, c-format
|
||||
msgid "Error: failed to compile sub filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:715 ../aa_status.c:731
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [OPTIONS]\n"
|
||||
"Legacy options and their equivalent command\n"
|
||||
" --profiled --count --profiles\n"
|
||||
" --enforced --count --profiles --mode=enforced\n"
|
||||
" --complaining --count --profiles --mode=complain\n"
|
||||
" --kill --count --profiles --mode=kill\n"
|
||||
" --prompt --count --profiles --mode=prompt\n"
|
||||
" --special-unconfined --count --profiles --mode=unconfined\n"
|
||||
" --process-mixed --count --ps --mode=mixed\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:734 ../aa_status.c:750
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage of filters\n"
|
||||
"Filters are used to reduce the output of information to only\n"
|
||||
"those entries that will match the filter. Filters use posix\n"
|
||||
"regular expression syntax. The possible values for exes that\n"
|
||||
"support filters are below\n"
|
||||
"\n"
|
||||
" --filter.mode: regular expression to match the profile "
|
||||
"mode modes: enforce, complain, kill, unconfined, mixed\n"
|
||||
" --filter.profiles: regular expression to match displayed profile names\n"
|
||||
" --filter.pid: regular expression to match displayed processes pids\n"
|
||||
" --filter.exe: regular expression to match executable\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:762 ../aa_status.c:778
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [OPTIONS]\n"
|
||||
"Displays various information about the currently loaded AppArmor policy.\n"
|
||||
"Default if no options given\n"
|
||||
" --show=all\n"
|
||||
"\n"
|
||||
"OPTIONS (one only):\n"
|
||||
" --enabled returns error code if AppArmor not enabled\n"
|
||||
" --show=X What information to show. {profiles,processes,all}\n"
|
||||
" --count print the number of entries. Implies --quiet\n"
|
||||
" --filter.mode=filter see filters\n"
|
||||
" --filter.profiles=filter see filters\n"
|
||||
" --filter.pid=filter see filters\n"
|
||||
" --filter.exe=filter see filters\n"
|
||||
" --json displays multiple data points in machine-readable JSON "
|
||||
"format\n"
|
||||
" --pretty-json same data as --json, formatted for human consumption as "
|
||||
"well\n"
|
||||
" --verbose (default) displays data points about loaded policy set\n"
|
||||
" --quiet don't output error messages\n"
|
||||
" -h[(legacy|filters)] this message, or info on the specified option\n"
|
||||
" --help[=(legacy|filters)] this message, or info on the specified option\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:856 ../aa_status.c:872
|
||||
#, c-format
|
||||
msgid "Error: Invalid --help option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:924 ../aa_status.c:940
|
||||
#, c-format
|
||||
msgid "Error: Invalid --show option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:946 ../aa_status.c:962
|
||||
msgid "Error: Invalid command.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:971 ../aa_status.c:987
|
||||
msgid "Error: Unknown options.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:983 ../aa_status.c:999
|
||||
#, c-format
|
||||
msgid "Error: failed to compile mode filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:988 ../aa_status.c:1004
|
||||
#, c-format
|
||||
msgid "Error: failed to compile profiles filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:994 ../aa_status.c:1010
|
||||
#, c-format
|
||||
msgid "Error: failed to compile ps filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1000 ../aa_status.c:1016
|
||||
#, c-format
|
||||
msgid "Error: failed to compile exe filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1015 ../aa_status.c:1031
|
||||
#, c-format
|
||||
msgid "Failed to open memstream: %m\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1026
|
||||
#, c-format
|
||||
msgid "Failed to get profiles: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1050
|
||||
#, c-format
|
||||
msgid "Failed to get processes: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1076 ../aa_status.c:1099
|
||||
msgid "Failed to parse json output"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1083 ../aa_status.c:1106
|
||||
msgid "Failed to print pretty json"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1044
|
||||
#, c-format
|
||||
msgid "Failed to retrieve profiles from kernel: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1073
|
||||
#, c-format
|
||||
msgid "Failed to get confinement information from processes: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1042
|
||||
msgid "No policy loaded into the kernel\n"
|
||||
msgstr ""
|
@@ -1,67 +0,0 @@
|
||||
# Belarusian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-05-05 21:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Belarusian <be@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-05-06 05:41+0000\n"
|
||||
"X-Generator: Launchpad (build fbdff7602bd10fb883bf7e2ddcc7fd5a16f60398)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Catalan translation for apparmor
|
||||
# Copyright (c) 2024 Rosetta Contributors and Canonical Ltd 2024
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2024-09-14 10:17+0000\n"
|
||||
"Last-Translator: Walter Garcia-Fontes <walter.garcia@upf.edu>\n"
|
||||
"Language-Team: Catalan <ca@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2024-09-15 07:16+0000\n"
|
||||
"X-Generator: Launchpad (build 1b1ed1ad2dbfc71ee62b5c5491c975135a771bf0)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opcions]\n"
|
||||
" opcions:\n"
|
||||
" -q | --quiet No imprimeixis cap missatge\n"
|
||||
" -h | --help Imprimeix l'ajuda\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opcions desconegudes o incompatibles\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opció desconeguda «%s»\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sí\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No - no esta disponible a aquest sistema\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No - desactivat a l'inici.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Potser - la interfície de política no està disponible.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Potser - permisos insuficient per determinar la disponibilitat.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Error - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Czech translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2022-01-09 11:59+0000\n"
|
||||
"Last-Translator: Marek Hladík <mhladik@seznam.cz>\n"
|
||||
"Language-Team: Czech <cs@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2022-01-10 06:32+0000\n"
|
||||
"X-Generator: Launchpad (build 1682fd44eec4f62371f0bed122a83482daf08e23)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "neznámé nebo nekompatibilní volby\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "neznámá volba '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ano\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ne - není v tomto systému k dispozici.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ne - zakázáno při startu.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Možná - rozhraní zásad není k dispozici.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Možná - nedostatečná oprávnění k určení dostupnosti.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Chyba - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# English (Australia) translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-11-28 04:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (Australia) <en_AU@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-11-29 06:26+0000\n"
|
||||
"X-Generator: Launchpad (build 12d09381f8e8eee3115395875b132e165fa96574)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,67 +0,0 @@
|
||||
# English (Canada) translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2021-10-01 04:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (Canada) <en_CA@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2021-10-02 06:17+0000\n"
|
||||
"X-Generator: Launchpad (build 1ce78163f6a09ed42b4201fe7d3f0e3a2eba7d02)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Estonian translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2023-07-04 08:52+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2023-07-05 04:31+0000\n"
|
||||
"X-Generator: Launchpad (build beda0e9dd2b131780db60fe479d4b43618b27243)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [valikud]\n"
|
||||
" valikud:\n"
|
||||
" -q | --quiet Ärge printige sõnumeid välja\n"
|
||||
" -h | --help Prindi abiinfo\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "tundmatud või ühildumatud valikud\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "tundmatu valik '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Jah\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ei – pole selles süsteemis saadaval.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ei – käivitamisel keelatud.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Võib-olla – poliisiliides pole saadaval.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Võib-olla - kättesaadavuse määramiseks pole piisavalt õigusi.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Viga – '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Galician translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-04-21 14:59+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Galician <gl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-04-22 06:10+0000\n"
|
||||
"X-Generator: Launchpad (build aad6b57d58e2f621954298e262c1cc904860f5d2)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Hebrew translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2023-10-05 05:12+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hebrew <he@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2023-10-06 08:32+0000\n"
|
||||
"X-Generator: Launchpad (build bd6cfd0cfc024dbe1dcd7d5d91165fb4f6a6c596)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [אפשרויות]\n"
|
||||
" אפשרויות:\n"
|
||||
" -q | --quiet לא להציג הודעות\n"
|
||||
" -h | --help הצגת עזרה\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "אפשרויות לא ידועות או לא נתמכות\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "האפשרות ‚%s’ לא מוכרת\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "כן\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "לא - לא זמין במערכת הזאת.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "לא - מושבת בעלייה.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "אולי - מנשק המדיניות לא זמין.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "אולי - אין מספיק הרשאות לקבוע זמינות.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "שגיאה - ‚%s’\n"
|
@@ -1,67 +0,0 @@
|
||||
# Hindi translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2023-01-09 07:39+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hindi <hi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2023-01-10 06:22+0000\n"
|
||||
"X-Generator: Launchpad (build 87bfee1fd14ea3245297d63eeec1e4c8a1d203a8)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Croatian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2021-10-03 10:17+0000\n"
|
||||
"Last-Translator: gogo <trebelnik2@gmail.com>\n"
|
||||
"Language-Team: Croatian <hr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2021-10-04 06:23+0000\n"
|
||||
"X-Generator: Launchpad (build 1ce78163f6a09ed42b4201fe7d3f0e3a2eba7d02)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [mogućnosti]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Ne prikazuj poruke\n"
|
||||
" -h | --help Prikaži pomoć\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "nepoznata ili nepotpuna mogućnost\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "nepoznata mogućnost '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Da\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ne - nedostupno na ovom sustavu.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ne - onemogućeno pri pokretanju.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Možda - pravilo sučelja nedostupno.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Možda - nedovoljna dozvola za određivanje dostupnosti.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Greška - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Italian translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2022-06-30 17:54+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Italian <it@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2022-07-01 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build f48158886a49da429840bcd298f0c7ed60f9ad7b)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opzioni]\n"
|
||||
" opzioni:\n"
|
||||
" -q | --quiet Non stampa nessun messaggio\n"
|
||||
" -h | --help Stampa la guida\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opzioni sconosciute o incompatibili\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opzione sconosciuta '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Si\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No - non disponibile su questo sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No - disabilitato all'avvio.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Forse - interfaccia dei criteri non disponibile.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Forse - autorizzazioni insufficienti per determinare la disponibilità.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Errore - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Georgian translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2023-06-26 15:06+0000\n"
|
||||
"Last-Translator: NorwayFun <temuri.doghonadze@gmail.com>\n"
|
||||
"Language-Team: Georgian <ka@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2023-06-27 04:31+0000\n"
|
||||
"X-Generator: Launchpad (build aedf8597c50c1abc5fb7f9e871e686dfcb381fde)\n"
|
||||
"Language: aa\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [პარამეტრები]\n"
|
||||
" პარამეტრები:\n"
|
||||
" -q | --quiet შეტყობინებები გამოტანილი არ იქნება\n"
|
||||
" -h | --help დახმარების გამოტანა\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "უცნობი ან შეუთავსებელი პარამეტრები\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "უცნობი პარამეტრი \"%s\"-სთვის\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "დიახ\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "არა - მიუწვდომელია ამ სისტემაზე\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "არა - გამორთულია ჩატვირთვისას\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "შეიძლება - პოლიტიკის ინტერფეისი ხელმისაწვდომი არაა.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "შეიძლება - არასაკმარისი წვდომები ხელმისაწვდომობის დასადგენად.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "შეცდომა - \"%s\"\n"
|
@@ -1,67 +0,0 @@
|
||||
# Kabyle translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-04-29 14:31+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Kabyle <kab@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-04-30 05:44+0000\n"
|
||||
"X-Generator: Launchpad (build fbdff7602bd10fb883bf7e2ddcc7fd5a16f60398)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,73 +0,0 @@
|
||||
# Burmese translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2022-06-26 11:50+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Burmese <my@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2022-06-27 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build 51a2e4fa2e9b8e45f00904ad7f53546f45ac48a5)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s- [options]\n"
|
||||
" ရွေးချယ်စရာများ-\n"
|
||||
" -q | --quiet မည်သည့်စာတိုကိုမှ ပရင့်မထုတ်ပါနှင့်။\n"
|
||||
" -h | --help ပရင့်အကူအညီ\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "အမည်မသိ သို့မဟုတ် သဟဇာတမဖြစ်သော ရွေးချယ်စရာများ\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "အမည်မသိရွေးချယ်မှု '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "ဟုတ်\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "မဟုတ်ပါ - ဤစနစ်တွင် မရနိုင်ပါ။\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "မဟုတ်ပါ - boot တွင် ပိတ်ထားပါသည်။\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "ဖြစ်နိုင်ပါသည် - မူဝါဒ interface ကို မရနိုင်ပါ။\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"ဖြစ်နိုင်ပါသည် - ရရှိနိုင်မှုကို ဆုံးဖြတ်ရန်အတွက် ခွင့်ပြုချက်များမှာ "
|
||||
"လုံလောက်မှုမရှိပါ။\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "အမှား- '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Occitan (post 1500) translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2021-01-14 18:26+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Occitan (post 1500) <oc@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2021-01-15 07:59+0000\n"
|
||||
"X-Generator: Launchpad (build 511b4a3b6512aa3d421c5f7d74f3527e78bff26e)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Polish translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2021-07-22 20:10+0000\n"
|
||||
"Last-Translator: Marek Adamski <Unknown>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2021-07-23 06:03+0000\n"
|
||||
"X-Generator: Launchpad (build 7edebbcd0516593cf020aaa3c59299732a7c73cc)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opcje]\n"
|
||||
" opcje:\n"
|
||||
" -q | --quiet Nie wyświetlaj żadnych komunikatów\n"
|
||||
" -h | --help Wyświetl pomoc\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "nieznane lub niekompatybilne opcje\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "nieznana opcja '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Tak\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nie - nie jest dostępne w tym systemie.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nie - wyłączone podczas rozruchu.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Może - interfejs zasad nie jest dostępny.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Może - brak wystarczających uprawnień do określenia dostępności.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Błąd - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Brazilian Portuguese translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-04-27 20:32+0000\n"
|
||||
"Last-Translator: Rodrigo Farias <Unknown>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-04-28 05:52+0000\n"
|
||||
"X-Generator: Launchpad (build d1105341713c5be348effe2a5142c4a210ce4cde)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" opções:\n"
|
||||
" -q | --quiet Não imprimir nenhum mensagem\n"
|
||||
" -h | --help Assistente de impressão\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opções incompatíveis ou desconhecidas\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opção desconhecida '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sim\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Não - não disponível neste sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Não - desabilitado na inicialização.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Talvez - interface de política não disponível.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Talvez - permissões insuficientes para determinar disponibilidade.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Erro - '%s'\n"
|
@@ -1,26 +1,21 @@
|
||||
# Romanian translation for apparmor, "apparmor-binutils" component.
|
||||
# Mesajele în limba română pentru pachetul „apparmor”, componenta „apparmor-binutils”.
|
||||
# Copyright © 2020 Rosetta Contributors and Canonical Ltd.
|
||||
# Copyright © 2024 Canonical Ltd.
|
||||
# Romanian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
#
|
||||
# Daniel Slavu <Unknown>, feb-2020.
|
||||
# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, sep-2024.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor-binutils\n"
|
||||
"Report-Msgid-Bugs-To: <apparmor@lists.ubuntu.com>\n"
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2024-09-23 22:45+0000\n"
|
||||
"Last-Translator: Remus-Gabriel Chelu <Unknown>\n"
|
||||
"Language-Team: Romanian <debian-l10n-romanian@lists.debian.org>\n"
|
||||
"PO-Revision-Date: 2020-02-20 21:47+0000\n"
|
||||
"Last-Translator: Daniel Slavu <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2024-09-25 04:33+0000\n"
|
||||
"X-Generator: Launchpad (build 1b1ed1ad2dbfc71ee62b5c5491c975135a771bf0)\n"
|
||||
"Language: ro\n"
|
||||
"X-Launchpad-Export-Date: 2020-02-21 05:39+0000\n"
|
||||
"X-Generator: Launchpad (build 19413b719a8df7423ab1390528edadce9e0e4aca)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
@@ -32,8 +27,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"%s: [opțiuni]\n"
|
||||
" opțiuni:\n"
|
||||
" -q | --quiet nu afișează niciun mesaj\n"
|
||||
" -h | --help imprimă ajutorul\n"
|
||||
" -q | --calm Nu imprima niciun mesaj\n"
|
||||
" -h | - ajutor Imprimare ajutor\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
@@ -43,7 +38,7 @@ msgstr "opțiuni necunoscute sau incompatibile\n"
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opțiune necunoscută „%s”\n"
|
||||
msgstr "opțiune necunoscută '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
@@ -63,8 +58,7 @@ msgstr "Nu - dezactivat la pornire.\n"
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
"Poate - interfața politică (de directive politice) nu este disponibilă.\n"
|
||||
msgstr "Poate - interfața politică nu este disponibilă.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
@@ -75,4 +69,4 @@ msgstr ""
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Eroare - „%s”\n"
|
||||
msgstr "Eroare - '%s'\n"
|
||||
|
@@ -1,67 +0,0 @@
|
||||
# Serbian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-11-23 18:06+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Serbian <sr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-11-24 05:55+0000\n"
|
||||
"X-Generator: Launchpad (build c35ff22711d15549e2303ae18ae521fd91f6bf00)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Ukrainian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-05-19 21:48+0000\n"
|
||||
"Last-Translator: Nazarii Ritter <nazariy.ritter@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <uk@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-05-20 05:42+0000\n"
|
||||
"X-Generator: Launchpad (build 0385b538081bc4718df6fb844a3afc89729c94ce)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [опції]\n"
|
||||
" опції:\n"
|
||||
" -q | --quiet Не виводити жодних повідомлень\n"
|
||||
" -h | --help Вивести довідку\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "невідомі або несумісні опції\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "невідомий параметр «%s»\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Так\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ні – недоступно на цій системі.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ні – вимкнено під час завантаження.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Можливо – інтерфейс політики недоступний.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Можливо – недостатньо дозволів для визначення наявності.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Помилка - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Chinese (Simplified) translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-05-14 09:16+0000\n"
|
||||
"Last-Translator: 玉堂白鹤 <yjwork@qq.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-05-15 05:51+0000\n"
|
||||
"X-Generator: Launchpad (build 0385b538081bc4718df6fb844a3afc89729c94ce)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [选项]\n"
|
||||
" 选项:\n"
|
||||
" -q | --quiet 不要打印任何消息\n"
|
||||
" -h | --help 打印帮助\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "未知或不兼容的选项\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "未知选项 '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "是\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "否 - 在此系统上不可用。\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "否 - 引导时被禁用。\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "也许 - 策略界面不可用\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "也许 - 没有足够的权限确定可用性。\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "错误 - '%s'\n"
|
@@ -35,14 +35,14 @@ VERSION=$(shell cat $(COMMONDIR)/Version)
|
||||
pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH)))))
|
||||
map = $(foreach a,$(2),$(call $(1),$(a)))
|
||||
|
||||
AWK?=$(or $(shell which awk),$(error awk utility required for build but not available))
|
||||
AWK?=$(or $(shell command -v awk),$(error awk utility required for build but not available))
|
||||
|
||||
define nl
|
||||
|
||||
|
||||
endef
|
||||
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || $(AWK) '{ print $2 }' common/.stamp_rev
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
|
||||
|
||||
ifndef PYTHON_VERSIONS
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python3)
|
||||
|
@@ -1 +1 @@
|
||||
5.0.0~alpha1
|
||||
4.1.0~beta3
|
||||
|
@@ -92,8 +92,6 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
||||
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
||||
fi
|
||||
|
||||
AC_PROG_CXX
|
||||
|
||||
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
|
||||
EXTRA_CFLAGS="-Wall $EXTRA_WARNINGS -fPIC"
|
||||
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||
@@ -101,7 +99,6 @@ 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_SUBST([AM_CXXFLAGS], ["$EXTRA_CFLAGS"])
|
||||
|
||||
AC_OUTPUT(
|
||||
Makefile
|
||||
|
@@ -22,15 +22,15 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa_change_hat - change to or from a "hat" within a AppArmor profile
|
||||
aa_change_hat - change to or from a "hat" within a AppArmor profile
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<#include E<lt>sys/apparmor.hE<gt>>
|
||||
|
||||
B<int aa_change_hat (const char *subprofile, unsigned long magic_token);>
|
||||
B<int aa_change_hat (char *subprofile, unsigned long magic_token);>
|
||||
|
||||
B<int aa_change_hatv (const char *subprofiles[], unsigned long magic_token);>
|
||||
B<int aa_change_hatv (char *subprofiles[], unsigned long magic_token);>
|
||||
|
||||
B<int aa_change_hat_vargs (unsigned long magic_token, ...);>
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa_change_profile, aa_change_onexec - change a task's profile
|
||||
aa_change_profile, aa_change_onexec - change a tasks profile
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -58,8 +58,8 @@ The aa_change_onexec() function is like the aa_change_profile() function
|
||||
except it specifies that the profile transition should take place on the
|
||||
next exec instead of immediately. The delayed profile change takes
|
||||
precedence over any exec transition rules within the confining profile.
|
||||
Delaying the profile boundary has a couple of advantages: it removes the
|
||||
need for stub transition profiles, and the exec boundary is a natural security
|
||||
Delaying the profile boundary has a couple of advantages, it removes the
|
||||
need for stub transition profiles and the exec boundary is a natural security
|
||||
layer where potentially sensitive memory is unmapped.
|
||||
|
||||
=head1 RETURN VALUE
|
||||
|
@@ -54,7 +54,7 @@ B<typedef struct aa_features aa_features;>
|
||||
|
||||
B<int aa_features_new(aa_features **features, int dirfd, const char *path);>
|
||||
|
||||
B<int aa_features_new_from_file(aa_features **features, int file);>
|
||||
B<int aa_features_new_from_file(aa_features **features, int fd);>
|
||||
|
||||
B<int aa_features_new_from_string(aa_features **features, const char *string, size_t size);>
|
||||
|
||||
|
@@ -58,9 +58,6 @@ appropriately.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
# podchecker warns about duplicate link targets for EACCES, EBUSY, ENOENT,
|
||||
# and ENOMEM, but this is a warning that is safe to ignore.
|
||||
|
||||
B<aa_is_enabled>
|
||||
|
||||
=over 4
|
||||
|
@@ -41,7 +41,7 @@ result is an intersection of all profiles which are stacked. Stacking profiles
|
||||
together is desirable when wanting to ensure that confinement will never become
|
||||
more permissive. When changing between two profiles, as performed with
|
||||
aa_change_profile(2), there is always the possibility that the new profile is
|
||||
more permissive than the old profile, but that possibility is eliminated when
|
||||
more permissive than the old profile but that possibility is eliminated when
|
||||
using aa_stack_profile().
|
||||
|
||||
To stack a profile with the current confinement context, a task can use the
|
||||
@@ -68,7 +68,7 @@ The aa_stack_onexec() function is like the aa_stack_profile() function
|
||||
except it specifies that the stacking should take place on the next exec
|
||||
instead of immediately. The delayed profile change takes precedence over any
|
||||
exec transition rules within the confining profile. Delaying the stacking
|
||||
boundary has a couple of advantages: it removes the need for stub transition
|
||||
boundary has a couple of advantages, it removes the need for stub transition
|
||||
profiles and the exec boundary is a natural security layer where potentially
|
||||
sensitive memory is unmapped.
|
||||
|
||||
|
@@ -19,10 +19,6 @@
|
||||
#ifndef __LIBAALOGPARSE_H_
|
||||
#define __LIBAALOGPARSE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AA_RECORD_EXEC_MMAP 1
|
||||
#define AA_RECORD_READ 2
|
||||
#define AA_RECORD_WRITE 4
|
||||
@@ -30,10 +26,10 @@ extern "C" {
|
||||
#define AA_RECORD_LINK 16
|
||||
|
||||
/**
|
||||
* Enum representing which syntax version the log entry used.
|
||||
* Support for V1 parsing was completely removed in 2011 and that enum entry
|
||||
* is only still there for API compatibility reasons.
|
||||
* This is just for convenience now that we have two
|
||||
* wildly different grammars.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AA_RECORD_SYNTAX_V1,
|
||||
@@ -52,23 +48,70 @@ typedef enum
|
||||
AA_RECORD_STATUS /* Configuration change */
|
||||
} aa_record_event_type;
|
||||
|
||||
/*
|
||||
* Use this preprocessor dance to maintain backcompat for field names
|
||||
* This will break C code that used the C++ reserved keywords "namespace"
|
||||
* and "class" as identifiers, but this is bad practice anyways, and we
|
||||
* hope that we are the only ones in a given C file that messed up this way
|
||||
/**
|
||||
* With the sole exception of active_hat, this is a 1:1
|
||||
* mapping from the keys that the new syntax uses.
|
||||
*
|
||||
* TODO: document this in a man page for aalogparse?
|
||||
*/
|
||||
#if defined(SWIG) && defined(__cplusplus)
|
||||
#error "SWIG and __cplusplus are defined together"
|
||||
#elif !defined(SWIG) && !defined(__cplusplus)
|
||||
/* Use SWIG's %rename feature to preserve backcompat */
|
||||
#define class rule_class
|
||||
#define namespace aa_namespace
|
||||
#endif
|
||||
* Some examples of the old syntax and how they're mapped with the aa_log_record struct:
|
||||
*
|
||||
* "PERMITTING r access to /path (program_name(12345) profile /profile active hat)"
|
||||
* - operation: access
|
||||
* - requested_mask: r
|
||||
* - pid: 12345
|
||||
* - profile: /profile
|
||||
* - name: /path
|
||||
* - info: program_name
|
||||
* - active_hat: hat
|
||||
*
|
||||
* "REJECTING mkdir on /path/to/something (bash(23415) profile /bin/freak-aa-out active /bin/freak-aa-out"
|
||||
* - operation: mkdir
|
||||
* - name: /path/to/something
|
||||
* - info: bash
|
||||
* - pid: 23415
|
||||
* - profile: /bin/freak-aa-out
|
||||
* - active_hat: /bin/freak-aa-out
|
||||
*
|
||||
* "REJECTING xattr set on /path/to/something (bash(23415) profile /bin/freak-aa-out active /bin/freak-aa-out)"
|
||||
* - operation: xattr
|
||||
* - attribute: set
|
||||
* - name: /path/to/something
|
||||
* - info: bash
|
||||
* - pid: 23415
|
||||
* - profile: /bin/freak-aa-out
|
||||
* - active_hat: /bin/freak-aa-out
|
||||
*
|
||||
* "PERMITTING attribute (something) change to /else (bash(23415) profile /bin/freak-aa-out active /bin/freak-aa-out)"
|
||||
* - operation: setattr
|
||||
* - attribute: something
|
||||
* - name: /else
|
||||
* - info: bash
|
||||
* - pid: 23415
|
||||
* - profile: /bin/freak-aa-out
|
||||
* - active_hat: /bin/freak-aa-out
|
||||
*
|
||||
* "PERMITTING access to capability 'cap' (bash(23415) profile /bin/freak-aa-out active /bin/freak-aa-out)"
|
||||
* - operation: capability
|
||||
* - name: cap
|
||||
* - info: bash
|
||||
* - pid: 23415
|
||||
* - profile: /bin/freak-aa-out
|
||||
* - active_hat: /bin/freak-aa-out
|
||||
*
|
||||
* "LOGPROF-HINT unknown_hat TESTHAT pid=27764 profile=/change_hat_test/test_hat active=/change_hat_test/test_hat"
|
||||
* - operation: change_hat
|
||||
* - name: TESTHAT
|
||||
* - info: unknown_hat
|
||||
* - pid: 27764
|
||||
* - profile: /change_hat_test/test_hat
|
||||
* - active_hat: /change_hat_test/test_hat
|
||||
*
|
||||
* "LOGPROF-HINT fork pid=27764 child=38229"
|
||||
* - operation: clone
|
||||
* - task: 38229
|
||||
* - pid: 27764
|
||||
**/
|
||||
|
||||
typedef struct aa_log_record
|
||||
typedef struct
|
||||
{
|
||||
aa_record_syntax_version version;
|
||||
aa_record_event_type event; /* Event type */
|
||||
@@ -91,7 +134,7 @@ typedef struct aa_log_record
|
||||
char *comm; /* Command that triggered msg */
|
||||
char *name;
|
||||
char *name2;
|
||||
char *aa_namespace;
|
||||
char *namespace;
|
||||
char *attribute;
|
||||
unsigned long parent;
|
||||
char *info;
|
||||
@@ -118,7 +161,7 @@ typedef struct aa_log_record
|
||||
char *flags;
|
||||
char *src_name;
|
||||
|
||||
char *rule_class;
|
||||
char *class;
|
||||
|
||||
char *net_addr;
|
||||
char *peer_addr;
|
||||
@@ -133,7 +176,7 @@ typedef struct aa_log_record
|
||||
* @return Parsed data.
|
||||
*/
|
||||
aa_log_record *
|
||||
parse_record(const char *str);
|
||||
parse_record(char *str);
|
||||
|
||||
/**
|
||||
* Frees all struct data.
|
||||
@@ -142,9 +185,5 @@ parse_record(const char *str);
|
||||
void
|
||||
free_record(aa_log_record *record);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -105,8 +105,8 @@ extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
#define AA_QUERY_CMD_LABEL "label"
|
||||
#define AA_QUERY_CMD_LABEL_SIZE sizeof(AA_QUERY_CMD_LABEL)
|
||||
|
||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allowed,
|
||||
int *audited);
|
||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||
int *audit);
|
||||
extern int aa_query_file_path_len(uint32_t mask, const char *label,
|
||||
size_t label_len, const char *path,
|
||||
size_t path_len, int *allowed, int *audited);
|
||||
@@ -152,16 +152,16 @@ extern int aa_features_new_from_kernel(aa_features **features);
|
||||
extern aa_features *aa_features_ref(aa_features *features);
|
||||
extern void aa_features_unref(aa_features *features);
|
||||
|
||||
extern int aa_features_write_to_fd(const aa_features *features, int fd);
|
||||
extern int aa_features_write_to_file(const aa_features *features,
|
||||
extern int aa_features_write_to_fd(aa_features *features, int fd);
|
||||
extern int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path);
|
||||
extern bool aa_features_is_equal(const aa_features *features1,
|
||||
const aa_features *features2);
|
||||
extern bool aa_features_is_equal(aa_features *features1,
|
||||
aa_features *features2);
|
||||
extern int aa_features_check(int dirfd, const char *path,
|
||||
aa_features *features);
|
||||
extern bool aa_features_supports(const aa_features *features, const char *str);
|
||||
extern char *aa_features_id(const aa_features *features);
|
||||
extern char *aa_features_value(const aa_features *features, const char *str, size_t *len);
|
||||
extern bool aa_features_supports(aa_features *features, const char *str);
|
||||
extern char *aa_features_id(aa_features *features);
|
||||
extern char *aa_features_value(aa_features *features, const char *str, size_t *len);
|
||||
|
||||
typedef struct aa_kernel_interface aa_kernel_interface;
|
||||
extern int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
|
||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 25
|
||||
AA_LIB_REVISION = 2
|
||||
AA_LIB_AGE = 24
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.24.2
|
||||
AA_LIB_CURRENT = 20
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 19
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.19.0
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -44,7 +44,7 @@ include $(COMMONDIR)/Make.rules
|
||||
|
||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -Wno-yacc -d -p aalogparse_
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
@@ -73,16 +73,6 @@ CLEANFILES = libapparmor.pc
|
||||
tst_aalogmisc_SOURCES = tst_aalogmisc.c
|
||||
tst_aalogmisc_LDADD = .libs/libapparmor.a
|
||||
|
||||
tst_aalogparse_cpp_SOURCES = tst_aalogparse_cpp.cpp
|
||||
tst_aalogparse_cpp_LDADD = .libs/libapparmor.a
|
||||
|
||||
tst_aalogparse_oldname_SOURCES = tst_aalogparse_oldname.c
|
||||
tst_aalogparse_oldname_LDADD = .libs/libapparmor.a
|
||||
|
||||
tst_aalogparse_reentrancy_SOURCES = tst_aalogparse_reentrancy.c
|
||||
tst_aalogparse_reentrancy_LDADD = .libs/libapparmor.a
|
||||
tst_aalogparse_reentrancy_LDFLAGS = -pthread
|
||||
|
||||
tst_features_SOURCES = tst_features.c
|
||||
tst_features_LDADD = .libs/libapparmor.a
|
||||
|
||||
@@ -90,7 +80,7 @@ tst_kernel_SOURCES = tst_kernel.c
|
||||
tst_kernel_LDADD = .libs/libapparmor.a
|
||||
tst_kernel_LDFLAGS = -pthread
|
||||
|
||||
check_PROGRAMS = tst_aalogmisc tst_aalogparse_cpp tst_aalogparse_reentrancy tst_aalogparse_oldname tst_features tst_kernel
|
||||
check_PROGRAMS = tst_aalogmisc tst_features tst_kernel
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
.PHONY: check-local
|
||||
|
@@ -399,10 +399,6 @@ 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 */
|
||||
@@ -608,11 +604,11 @@ void aa_features_unref(aa_features *features)
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set
|
||||
*/
|
||||
int aa_features_write_to_fd(const aa_features *features, int fd)
|
||||
int aa_features_write_to_fd(aa_features *features, int fd)
|
||||
{
|
||||
size_t size;
|
||||
ssize_t retval;
|
||||
const char *string;
|
||||
char *string;
|
||||
|
||||
string = features->string;
|
||||
size = strlen(string);
|
||||
@@ -636,7 +632,7 @@ int aa_features_write_to_fd(const aa_features *features, int fd)
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set
|
||||
*/
|
||||
int aa_features_write_to_file(const aa_features *features,
|
||||
int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path)
|
||||
{
|
||||
autoclose int fd = -1;
|
||||
@@ -657,7 +653,7 @@ int aa_features_write_to_file(const aa_features *features,
|
||||
*
|
||||
* Returns: true if they're equal, false if they're not or either are NULL
|
||||
*/
|
||||
bool aa_features_is_equal(const aa_features *features1, const aa_features *features2)
|
||||
bool aa_features_is_equal(aa_features *features1, aa_features *features2)
|
||||
{
|
||||
return features1 && features2 &&
|
||||
strcmp(features1->string, features2->string) == 0;
|
||||
@@ -701,7 +697,7 @@ int aa_features_check(int dirfd, const char *path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *features_lookup(const aa_features *features, const char *str)
|
||||
static const char *features_lookup(aa_features *features, const char *str)
|
||||
{
|
||||
const char *features_string = features->string;
|
||||
struct component components[32];
|
||||
@@ -743,7 +739,7 @@ static const char *features_lookup(const aa_features *features, const char *str)
|
||||
*
|
||||
* Returns: a bool specifying the support status of @str feature
|
||||
*/
|
||||
bool aa_features_supports(const aa_features *features, const char *str)
|
||||
bool aa_features_supports(aa_features *features, const char *str)
|
||||
{
|
||||
const char *value = features_lookup(features, str);
|
||||
|
||||
@@ -764,7 +760,7 @@ bool aa_features_supports(const aa_features *features, const char *str)
|
||||
* EISDIR - @str is not a leaf node in the feature tree
|
||||
*/
|
||||
|
||||
char *aa_features_value(const aa_features *features, const char *str, size_t *len)
|
||||
char *aa_features_value(aa_features *features, const char *str, size_t *len)
|
||||
{
|
||||
const char *start, *cur = features_lookup(features, str);
|
||||
|
||||
@@ -807,7 +803,7 @@ char *aa_features_value(const aa_features *features, const char *str, size_t *le
|
||||
* Returns: a string identifying @features which must be freed by the
|
||||
* caller or NULL, with errno set, upon error
|
||||
*/
|
||||
char *aa_features_id(const aa_features *features)
|
||||
char *aa_features_id(aa_features *features)
|
||||
{
|
||||
return strdup(features->hash);
|
||||
}
|
||||
|
@@ -15,15 +15,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* aalogparse_error now requires visibility of the aa_log_record type
|
||||
* Also include in a %code requires block to add it to the header
|
||||
*/
|
||||
%code requires{
|
||||
#include <aalogparse.h>
|
||||
}
|
||||
|
||||
%{
|
||||
|
||||
/* set the following to non-zero to get bison to emit debugging
|
||||
* information about tokens given and rules matched.
|
||||
* Also:
|
||||
* Uncomment the %defines
|
||||
* parse.error
|
||||
* parse.trace
|
||||
*/
|
||||
#define YYDEBUG 0
|
||||
#include <string.h>
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
@@ -39,10 +41,12 @@
|
||||
#define debug_unused_ unused_
|
||||
#endif
|
||||
|
||||
aa_log_record *ret_record;
|
||||
|
||||
/* Since we're a library, on any errors we don't want to print out any
|
||||
* error messages. We should probably add a debug interface that does
|
||||
* emit messages when asked for. */
|
||||
void aalogparse_error(unused_ void *scanner, aa_log_record *ret_record, debug_unused_ char const *s)
|
||||
void aalogparse_error(unused_ void *scanner, debug_unused_ char const *s)
|
||||
{
|
||||
#if (YYDEBUG != 0)
|
||||
printf("ERROR: %s\n", s);
|
||||
@@ -85,10 +89,9 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%define parse.trace
|
||||
*/
|
||||
|
||||
%define api.pure full
|
||||
%define api.pure
|
||||
%lex-param{void *scanner}
|
||||
%parse-param{void *scanner}
|
||||
%parse-param{aa_log_record *ret_record}
|
||||
|
||||
%union
|
||||
{
|
||||
@@ -281,9 +284,8 @@ audit_user_msg: TOK_KEY_MSG TOK_EQUALS audit_id audit_user_msg_tail
|
||||
|
||||
audit_id: TOK_AUDIT TOK_OPEN_PAREN TOK_AUDIT_DIGITS TOK_PERIOD TOK_AUDIT_DIGITS TOK_COLON TOK_AUDIT_DIGITS TOK_CLOSE_PAREN TOK_COLON
|
||||
{
|
||||
if (!asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7)) {
|
||||
yyerror(scanner, ret_record, YY_("Out of memory"));
|
||||
}
|
||||
if (!asprintf(&ret_record->audit_id, "%s.%s:%s", $3, $5, $7))
|
||||
yyerror(scanner, YY_("Out of memory"));
|
||||
ret_record->epoch = atol($3);
|
||||
ret_record->audit_sub_id = atoi($7);
|
||||
free($3);
|
||||
@@ -306,7 +308,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
| TOK_KEY_NAME TOK_EQUALS safe_string
|
||||
{ ret_record->name = $3;}
|
||||
| TOK_KEY_NAMESPACE TOK_EQUALS safe_string
|
||||
{ ret_record->aa_namespace = $3;}
|
||||
{ ret_record->namespace = $3;}
|
||||
| TOK_KEY_NAME2 TOK_EQUALS safe_string
|
||||
{ ret_record->name2 = $3;}
|
||||
| TOK_KEY_MASK TOK_EQUALS TOK_QUOTED_STRING
|
||||
@@ -438,7 +440,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->info = $1;
|
||||
}
|
||||
| TOK_KEY_CLASS TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->rule_class = $3; }
|
||||
{ ret_record->class = $3; }
|
||||
;
|
||||
|
||||
apparmor_event:
|
||||
@@ -475,3 +477,31 @@ protocol: TOK_QUOTED_STRING
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
||||
aa_log_record *
|
||||
_parse_yacc(char *str)
|
||||
{
|
||||
/* yydebug = 1; */
|
||||
YY_BUFFER_STATE lex_buf;
|
||||
yyscan_t scanner;
|
||||
|
||||
ret_record = NULL;
|
||||
ret_record = malloc(sizeof(aa_log_record));
|
||||
|
||||
_init_log_record(ret_record);
|
||||
|
||||
if (ret_record == NULL)
|
||||
return NULL;
|
||||
|
||||
#if (YYDEBUG != 0)
|
||||
yydebug = 1;
|
||||
#endif
|
||||
|
||||
aalogparse_lex_init(&scanner);
|
||||
lex_buf = aalogparse__scan_string(str, scanner);
|
||||
/* Ignore return value to return an AA_RECORD_INVALID event */
|
||||
(void)aalogparse_parse(scanner);
|
||||
aalogparse__delete_buffer(lex_buf, scanner);
|
||||
aalogparse_lex_destroy(scanner);
|
||||
return ret_record;
|
||||
}
|
||||
|
@@ -34,42 +34,13 @@
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
|
||||
#include "grammar.h"
|
||||
#include "scanner.h"
|
||||
|
||||
/* This is mostly just a wrapper around the code in grammar.y */
|
||||
aa_log_record *parse_record(const char *str)
|
||||
aa_log_record *parse_record(char *str)
|
||||
{
|
||||
YY_BUFFER_STATE lex_buf;
|
||||
yyscan_t scanner;
|
||||
aa_log_record *ret_record;
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
ret_record = malloc(sizeof(aa_log_record));
|
||||
|
||||
_init_log_record(ret_record);
|
||||
|
||||
if (ret_record == NULL)
|
||||
return NULL;
|
||||
|
||||
struct string_buf string_buf = {.buf = NULL, .buf_len = 0, .buf_alloc = 0};
|
||||
|
||||
#if (YYDEBUG != 0)
|
||||
/* Warning: this is still a global even in reentrant parsers */
|
||||
aalogparse_debug = 1;
|
||||
#endif
|
||||
|
||||
aalogparse_lex_init_extra(&string_buf, &scanner);
|
||||
lex_buf = aalogparse__scan_string(str, scanner);
|
||||
/* Ignore return value to return an AA_RECORD_INVALID event */
|
||||
(void)aalogparse_parse(scanner, ret_record);
|
||||
aalogparse__delete_buffer(lex_buf, scanner);
|
||||
aalogparse_lex_destroy(scanner);
|
||||
/* free(NULL) is a no-op */
|
||||
free(string_buf.buf);
|
||||
return ret_record;
|
||||
return _parse_yacc(str);
|
||||
}
|
||||
|
||||
void free_record(aa_log_record *record)
|
||||
@@ -92,8 +63,8 @@ void free_record(aa_log_record *record)
|
||||
free(record->name);
|
||||
if (record->name2 != NULL)
|
||||
free(record->name2);
|
||||
if (record->aa_namespace != NULL)
|
||||
free(record->aa_namespace);
|
||||
if (record->namespace != NULL)
|
||||
free(record->namespace);
|
||||
if (record->attribute != NULL)
|
||||
free(record->attribute);
|
||||
if (record->info != NULL)
|
||||
@@ -139,8 +110,8 @@ void free_record(aa_log_record *record)
|
||||
if (record->execpath != NULL)
|
||||
free(record->execpath);
|
||||
|
||||
if (record->rule_class != NULL)
|
||||
free(record->rule_class);
|
||||
if (record->class != NULL)
|
||||
free(record->class);
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
@@ -19,14 +19,8 @@
|
||||
#ifndef __AA_LOG_PARSER_H__
|
||||
#define __AA_LOG_PARSER_H__
|
||||
|
||||
// Internal-only type
|
||||
struct string_buf {
|
||||
char *buf;
|
||||
unsigned int buf_len;
|
||||
unsigned int buf_alloc;
|
||||
};
|
||||
|
||||
extern void _init_log_record(aa_log_record *record);
|
||||
extern aa_log_record *_parse_yacc(char *str);
|
||||
extern char *hex_to_string(char *str);
|
||||
extern char *ipproto_to_string(unsigned int proto);
|
||||
|
||||
|
@@ -19,7 +19,6 @@
|
||||
%option nounput
|
||||
%option noyy_top_state
|
||||
%option reentrant
|
||||
%option extra-type="struct string_buf*"
|
||||
%option prefix="aalogparse_"
|
||||
%option bison-bridge
|
||||
%option header-file="scanner.h"
|
||||
@@ -35,37 +34,40 @@
|
||||
|
||||
#define YY_NO_INPUT
|
||||
|
||||
void string_buf_reset(struct string_buf* char_buf)
|
||||
unsigned int string_buf_alloc = 0;
|
||||
unsigned int string_buf_len = 0;
|
||||
char *string_buf = NULL;
|
||||
|
||||
void string_buf_reset()
|
||||
{
|
||||
/* rewind buffer to zero, possibly doing initial allocation too */
|
||||
char_buf->buf_len = 0;
|
||||
if (char_buf->buf == NULL) {
|
||||
char_buf->buf_alloc = 128;
|
||||
char_buf->buf = malloc(char_buf->buf_alloc);
|
||||
assert(char_buf->buf != NULL);
|
||||
string_buf_len = 0;
|
||||
if (string_buf == NULL) {
|
||||
string_buf_alloc = 128;
|
||||
string_buf = malloc(string_buf_alloc);
|
||||
assert(string_buf != NULL);
|
||||
}
|
||||
/* always start with a valid but empty string */
|
||||
char_buf->buf[0] = '\0';
|
||||
string_buf[0] = '\0';
|
||||
}
|
||||
|
||||
void string_buf_append(struct string_buf* char_buf, unsigned int length, char *text)
|
||||
void string_buf_append(unsigned int length, char *text)
|
||||
{
|
||||
unsigned int current_length = char_buf->buf_len;
|
||||
unsigned int current_length = string_buf_len;
|
||||
|
||||
/* handle calling ..._append before ..._reset */
|
||||
if (char_buf->buf == NULL) string_buf_reset(char_buf);
|
||||
if (string_buf == NULL) string_buf_reset();
|
||||
|
||||
char_buf->buf_len += length;
|
||||
string_buf_len += length;
|
||||
/* expand allocation if this append would exceed the allocation */
|
||||
while (char_buf->buf_len >= char_buf->buf_alloc) {
|
||||
// TODO: overflow?
|
||||
char_buf->buf_alloc *= 2;
|
||||
char_buf->buf = realloc(char_buf->buf, char_buf->buf_alloc);
|
||||
assert(char_buf->buf != NULL);
|
||||
while (string_buf_len >= string_buf_alloc) {
|
||||
string_buf_alloc *= 2;
|
||||
string_buf = realloc(string_buf, string_buf_alloc);
|
||||
assert(string_buf != NULL);
|
||||
}
|
||||
/* copy and unconditionally terminate */
|
||||
memcpy(char_buf->buf+current_length, text, length);
|
||||
char_buf->buf[char_buf->buf_len] = '\0';
|
||||
memcpy(string_buf+current_length, text, length);
|
||||
string_buf[string_buf_len] = '\0';
|
||||
}
|
||||
|
||||
%}
|
||||
@@ -230,7 +232,7 @@ yy_flex_debug = 0;
|
||||
{open_paren} { return(TOK_OPEN_PAREN); }
|
||||
{close_paren} { BEGIN(INITIAL); return(TOK_CLOSE_PAREN); }
|
||||
{ws} { }
|
||||
\" { string_buf_reset(yyextra); BEGIN(quoted_string); }
|
||||
\" { string_buf_reset(); BEGIN(quoted_string); }
|
||||
{ID}+ {
|
||||
yylval->t_str = strdup(yytext);
|
||||
BEGIN(INITIAL);
|
||||
@@ -239,20 +241,20 @@ yy_flex_debug = 0;
|
||||
{equals} { return(TOK_EQUALS); }
|
||||
}
|
||||
|
||||
\" { string_buf_reset(yyextra); BEGIN(quoted_string); }
|
||||
\" { string_buf_reset(); BEGIN(quoted_string); }
|
||||
<quoted_string>\" { /* End of the quoted string */
|
||||
BEGIN(INITIAL);
|
||||
yylval->t_str = strdup(yyextra->buf);
|
||||
yylval->t_str = strdup(string_buf);
|
||||
return(TOK_QUOTED_STRING);
|
||||
}
|
||||
|
||||
|
||||
<quoted_string>\\(.|\n) { string_buf_append(yyextra, 1, &yytext[1]); }
|
||||
<quoted_string>\\(.|\n) { string_buf_append(1, &yytext[1]); }
|
||||
|
||||
<quoted_string>[^\\\n\"]+ { string_buf_append(yyextra, yyleng, yytext); }
|
||||
<quoted_string>[^\\\n\"]+ { string_buf_append(yyleng, yytext); }
|
||||
|
||||
<safe_string>{
|
||||
\" { string_buf_reset(yyextra); BEGIN(quoted_string); }
|
||||
\" { string_buf_reset(); BEGIN(quoted_string); }
|
||||
{hexstring} { yylval->t_str = hex_to_string(yytext); BEGIN(INITIAL); return(TOK_HEXSTRING);}
|
||||
{equals} { return(TOK_EQUALS); }
|
||||
. { /* eek, error! try another state */ BEGIN(INITIAL); yyless(0); }
|
||||
|
@@ -1,20 +0,0 @@
|
||||
#include <aalogparse.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
const char* log_line = "[23342.075380] audit: type=1400 audit(1725487203.971:1831): apparmor=\"DENIED\" operation=\"open\" class=\"file\" profile=\"snap-update-ns.firmware-updater\" name=\"/proc/202964/maps\" pid=202964 comm=\"5\" requested_mask=\"r\" denied_mask=\"r\" fsuid=1000 ouid=0";
|
||||
|
||||
int main(void) {
|
||||
int rc = 0;
|
||||
|
||||
/* Very basic test to ensure we can do aalogparse stuff in C++ */
|
||||
aa_log_record *record = parse_record(log_line);
|
||||
MY_TEST(record != NULL, "Log failed to parse");
|
||||
MY_TEST(record->version == AA_RECORD_SYNTAX_V2, "Log should have parsed as v2 form");
|
||||
MY_TEST(record->aa_namespace == NULL, "Log should have NULL namespace");
|
||||
MY_TEST((record->rule_class != NULL) && (strcmp(record->rule_class, "file") == 0), "Log should have file class");
|
||||
free_record(record);
|
||||
|
||||
return rc;
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
#include <aalogparse.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
const char* log_line = "[23342.075380] audit: type=1400 audit(1725487203.971:1831): apparmor=\"DENIED\" operation=\"open\" class=\"file\" profile=\"snap-update-ns.firmware-updater\" name=\"/proc/202964/maps\" pid=202964 comm=\"5\" requested_mask=\"r\" denied_mask=\"r\" fsuid=1000 ouid=0";
|
||||
|
||||
int main(void) {
|
||||
int rc = 0;
|
||||
|
||||
/* Very basic test to ensure we can use the C++-incompatible field names */
|
||||
aa_log_record *record = parse_record(log_line);
|
||||
MY_TEST(record != NULL, "Log failed to parse");
|
||||
MY_TEST(record->version == AA_RECORD_SYNTAX_V2, "Log should have parsed as v2 form");
|
||||
MY_TEST(record->namespace == NULL, "Log should have NULL namespace");
|
||||
MY_TEST((record->class != NULL) && (strcmp(record->class, "file") == 0), "Log should have file class");
|
||||
free_record(record);
|
||||
|
||||
return rc;
|
||||
}
|
@@ -1,154 +0,0 @@
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <aalogparse.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
const char* log_line = "[23342.075380] audit: type=1400 audit(1725487203.971:1831): apparmor=\"DENIED\" operation=\"open\" class=\"file\" profile=\"snap-update-ns.firmware-updater\" name=\"/proc/202964/maps\" pid=202964 comm=\"5\" requested_mask=\"r\" denied_mask=\"r\" fsuid=1000 ouid=0";
|
||||
const char* log_line_2 = "[ 4074.372559] audit: type=1400 audit(1725553393.143:793): apparmor=\"DENIED\" operation=\"capable\" class=\"cap\" profile=\"/usr/lib/snapd/snap-confine\" pid=19034 comm=\"snap-confine\" capability=12 capname=\"net_admin\"";
|
||||
|
||||
static int pthread_barrier_ok(int barrier_result) {
|
||||
return barrier_result == 0 || barrier_result == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
static int nullcmp_and_strcmp(const void *s1, const void *s2)
|
||||
{
|
||||
/* Return 0 if both pointers are NULL & non-zero if only one is NULL */
|
||||
if (!s1 || !s2)
|
||||
return s1 != s2;
|
||||
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
|
||||
int aa_log_record_eq(aa_log_record *record1, aa_log_record *record2) {
|
||||
int are_eq = 1;
|
||||
|
||||
are_eq &= (record1->version == record2->version);
|
||||
are_eq &= (record1->event == record2->event);
|
||||
are_eq &= (record1->pid == record2->pid);
|
||||
are_eq &= (record1->peer_pid == record2->peer_pid);
|
||||
are_eq &= (record1->task == record2->task);
|
||||
are_eq &= (record1->magic_token == record2->magic_token);
|
||||
are_eq &= (record1->epoch == record2->epoch);
|
||||
are_eq &= (record1->audit_sub_id == record2->audit_sub_id);
|
||||
|
||||
are_eq &= (record1->bitmask == record2->bitmask);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->audit_id, record2->audit_id) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->operation, record2->operation) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->denied_mask, record2->denied_mask) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->requested_mask, record2->requested_mask) == 0);
|
||||
are_eq &= (record1->fsuid == record2->fsuid);
|
||||
are_eq &= (record1->ouid == record2->ouid);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->profile, record2->profile) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->peer_profile, record2->peer_profile) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->comm, record2->comm) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->name, record2->name) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->name2, record2->name2) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->namespace, record2->namespace) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->attribute, record2->attribute) == 0);
|
||||
are_eq &= (record1->parent == record2->parent);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->info, record2->info) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->peer_info, record2->peer_info) == 0);
|
||||
are_eq &= (record1->error_code == record2->error_code);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->active_hat, record2->active_hat) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_family, record2->net_family) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_protocol, record2->net_protocol) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_sock_type, record2->net_sock_type) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_local_addr, record2->net_local_addr) == 0);
|
||||
are_eq &= (record1->net_local_port == record2->net_local_port);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_foreign_addr, record2->net_foreign_addr) == 0);
|
||||
are_eq &= (record1->net_foreign_port == record2->net_foreign_port);
|
||||
|
||||
are_eq &= (nullcmp_and_strcmp(record1->execpath, record2->execpath) == 0);
|
||||
|
||||
are_eq &= (nullcmp_and_strcmp(record1->dbus_bus, record2->dbus_bus) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->dbus_path, record2->dbus_path) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->dbus_interface, record2->dbus_interface) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->dbus_member, record2->dbus_member) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->signal, record2->signal) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->peer, record2->peer) == 0);
|
||||
|
||||
are_eq &= (nullcmp_and_strcmp(record1->fs_type, record2->fs_type) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->flags, record2->flags) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->src_name, record2->src_name) == 0);
|
||||
|
||||
are_eq &= (nullcmp_and_strcmp(record1->class, record2->class) == 0);
|
||||
|
||||
are_eq &= (nullcmp_and_strcmp(record1->net_addr, record2->net_addr) == 0);
|
||||
are_eq &= (nullcmp_and_strcmp(record1->peer_addr, record2->peer_addr) == 0);
|
||||
return are_eq;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* log;
|
||||
pthread_barrier_t *barrier;
|
||||
} pthread_parse_args;
|
||||
|
||||
void* pthread_parse_log(void* args) {
|
||||
pthread_parse_args *args_real = (pthread_parse_args *) args;
|
||||
int barrier_wait_result = pthread_barrier_wait(args_real->barrier);
|
||||
/* Return NULL and fail test if barrier wait fails */
|
||||
if (!pthread_barrier_ok(barrier_wait_result)) {
|
||||
return NULL;
|
||||
}
|
||||
aa_log_record *record = parse_record(args_real->log);
|
||||
return (void*) record;
|
||||
}
|
||||
|
||||
#define NUM_THREADS 16
|
||||
|
||||
int main(void) {
|
||||
pthread_t thread_ids[NUM_THREADS];
|
||||
pthread_barrier_t barrier;
|
||||
int barrier_wait_result;
|
||||
aa_log_record* parsed_logs[NUM_THREADS];
|
||||
int rc = 0;
|
||||
/* Set up arguments to be passed to threads */
|
||||
pthread_parse_args args = {.log=log_line, .barrier=&barrier};
|
||||
pthread_parse_args args2 = {.log=log_line_2, .barrier=&barrier};
|
||||
|
||||
MY_TEST(NUM_THREADS > 2, "Test requires more than 2 threads");
|
||||
|
||||
/* Use barrier to synchronize the start of log parsing among all the threads
|
||||
* This increases the likelihood of tickling race conditions, if there are any
|
||||
*/
|
||||
MY_TEST(pthread_barrier_init(&barrier, NULL, NUM_THREADS+1) == 0,
|
||||
"Could not init pthread barrier");
|
||||
for (int i=0; i<NUM_THREADS; i++) {
|
||||
if (i%2 == 0) {
|
||||
pthread_create(&thread_ids[i], NULL, pthread_parse_log, (void *) &args);
|
||||
} else {
|
||||
pthread_create(&thread_ids[i], NULL, pthread_parse_log, (void *) &args2);
|
||||
}
|
||||
}
|
||||
/* Final barrier_wait to set off the thread race */
|
||||
barrier_wait_result = pthread_barrier_wait(&barrier);
|
||||
MY_TEST(pthread_barrier_ok(barrier_wait_result), "Could not wait on pthread barrier");
|
||||
|
||||
/* Wait for threads to finish parsing the logs */
|
||||
for (int i=0; i<NUM_THREADS; i++) {
|
||||
MY_TEST(pthread_join(thread_ids[i], (void*) &parsed_logs[i]) == 0, "Could not join thread");
|
||||
}
|
||||
|
||||
/* Check that all logs parsed and are equal */
|
||||
for (int i=0; i<NUM_THREADS; i++) {
|
||||
MY_TEST(parsed_logs[i] != NULL, "Log failed to parse");
|
||||
MY_TEST(parsed_logs[i]->version == AA_RECORD_SYNTAX_V2, "Log should have parsed as v2 form");
|
||||
MY_TEST(parsed_logs[i]->event == AA_RECORD_DENIED, "Log should have parsed as denied");
|
||||
|
||||
/* Also check i==0 and i==1 as a sanity check for aa_log_record_eq */
|
||||
if (i%2 == 0) {
|
||||
MY_TEST(aa_log_record_eq(parsed_logs[0], parsed_logs[i]), "Log 0 != Log even");
|
||||
} else {
|
||||
MY_TEST(aa_log_record_eq(parsed_logs[1], parsed_logs[i]), "Log 1 != Log odd");
|
||||
}
|
||||
}
|
||||
MY_TEST(!aa_log_record_eq(parsed_logs[0], parsed_logs[1]), "Log 0 and log 1 shouldn't be equal");
|
||||
/* Clean up */
|
||||
MY_TEST(pthread_barrier_destroy(&barrier) == 0, "Could not destroy pthread barrier");
|
||||
for (int i=0; i<NUM_THREADS; i++) {
|
||||
free_record(parsed_logs[i]);
|
||||
}
|
||||
return rc;
|
||||
}
|
@@ -1,3 +1,3 @@
|
||||
SUBDIRS = perl python ruby
|
||||
|
||||
EXTRA_DIST = SWIG/*.i
|
||||
EXTRA_DIST = SWIG/*.i java/Makefile.am
|
||||
|
@@ -5,98 +5,9 @@
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/apparmor_private.h>
|
||||
|
||||
// Include static_assert if the C compiler supports it
|
||||
// static_assert standardized since C11, assert.h not needed since C23
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
|
||||
#include <assert.h>
|
||||
#endif
|
||||
%}
|
||||
|
||||
%include "typemaps.i"
|
||||
%include <cstring.i>
|
||||
%include <stdint.i>
|
||||
%include <exception.i>
|
||||
|
||||
/*
|
||||
* SWIG 4.3 included https://github.com/swig/swig/pull/2907 to distinguish
|
||||
* between Py_None being returned as a default void and Py_None being returned
|
||||
* as the equivalent of C NULL. Unfortunately, this turns into an API breaking
|
||||
* change with our use of %append_output when we want the Python function to
|
||||
* return something even when the C function has a void return type. Thus, we
|
||||
* need an additional macro to smooth over the differences. Include all affected
|
||||
* languages, even ones we don't build bindings for, for completeness.
|
||||
*/
|
||||
#if SWIG_VERSION >= 0x040300
|
||||
#ifdef SWIGPYTHON
|
||||
#define ISVOID_APPEND_OUTPUT(value) {$result = SWIG_Python_AppendOutput($result, value, 1);}
|
||||
#elif defined(SWIGRUBY)
|
||||
#define ISVOID_APPEND_OUTPUT(value) {$result = SWIG_Ruby_AppendOutput($result, value, 1);}
|
||||
#elif defined(SWIGPHP)
|
||||
#define ISVOID_APPEND_OUTPUT(value) {$result = SWIG_Php_AppendOutput($result, value, 1);}
|
||||
#else
|
||||
#define ISVOID_APPEND_OUTPUT(value) %append_output(value)
|
||||
#endif
|
||||
#else
|
||||
#define ISVOID_APPEND_OUTPUT(value) %append_output(value)
|
||||
#endif
|
||||
|
||||
%newobject parse_record;
|
||||
%delobject free_record;
|
||||
/*
|
||||
* Despite its name, %delobject does not hook up destructors to language
|
||||
* deletion mechanisms. Instead, it sets flags so that manually calling the
|
||||
* free function and then deleting by language mechanisms doesn't cause a
|
||||
* double-free.
|
||||
*
|
||||
* Additionally, we can manually extend the struct with a C++-like
|
||||
* destructor. This ensures that the record struct is freed
|
||||
* automatically when the high-level object goes out of scope.
|
||||
*/
|
||||
%extend aa_log_record {
|
||||
~aa_log_record() {
|
||||
free_record($self);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a no-op free_record wrapper to avoid making a double-free footgun.
|
||||
* Use rename directive to avoid colliding with the actual free_record, which
|
||||
* we use above to clean up when the higher-level language deletes the object.
|
||||
*
|
||||
* Ideally we would not expose a free_record at all, but we need to maintain
|
||||
* backwards compatibility with the existing high-level code that uses it.
|
||||
*/
|
||||
%rename(free_record) noop_free_record;
|
||||
#ifdef SWIGPYTHON
|
||||
%pythonprepend noop_free_record %{
|
||||
import warnings
|
||||
warnings.warn("free_record is now a no-op as the record's memory is handled automatically", DeprecationWarning)
|
||||
%}
|
||||
#endif
|
||||
%feature("autodoc",
|
||||
"This function used to free aa_log_record objects. Freeing is now handled "
|
||||
"automatically, so this no-op function remains for backwards compatibility.") noop_free_record;
|
||||
%inline %{
|
||||
void noop_free_record(aa_log_record *record) {(void) record;}
|
||||
%}
|
||||
|
||||
/*
|
||||
* Do not autogenerate a wrapper around free_record. This does not prevent us
|
||||
* from calling it ourselves in %extend C code.
|
||||
*/
|
||||
%ignore free_record;
|
||||
|
||||
|
||||
/*
|
||||
* Map names to preserve backwards compatibility
|
||||
*/
|
||||
#ifdef SWIGPYTHON
|
||||
%rename("_class") aa_log_record::rule_class;
|
||||
#else
|
||||
%rename("class") aa_log_record::rule_class;
|
||||
#endif
|
||||
%rename("namespace") aa_log_record::aa_namespace;
|
||||
|
||||
%include <aalogparse.h>
|
||||
|
||||
/**
|
||||
@@ -110,75 +21,18 @@ warnings.warn("free_record is now a no-op as the record's memory is handled auto
|
||||
|
||||
/* apparmor.h */
|
||||
|
||||
/*
|
||||
* label is a heap-allocated pointer, but when label and mode occur together,
|
||||
* the freeing of label must be deferred because mode points into label.
|
||||
*
|
||||
* %cstring_output_allocate((char **label, char **mode), free(*$1))
|
||||
* does not handle multi-argument typemaps correctly, so we write our own
|
||||
* typemap based on it instead.
|
||||
*/
|
||||
%typemap(in,noblock=1,numinputs=0) (char **label, char **mode) ($*1_ltype temp_label = 0, $*2_ltype temp_mode = 0) {
|
||||
$1 = &temp_label;
|
||||
$2 = &temp_mode;
|
||||
}
|
||||
%typemap(freearg,match="in") (char **label, char **mode) ""
|
||||
%typemap(argout,noblock=1,fragment="SWIG_FromCharPtr") (char **label, char **mode) {
|
||||
ISVOID_APPEND_OUTPUT(SWIG_FromCharPtr(*$1));
|
||||
ISVOID_APPEND_OUTPUT(SWIG_FromCharPtr(*$2));
|
||||
free(*$1);
|
||||
}
|
||||
|
||||
/*
|
||||
* mode also occurs in combination with con in aa_splitcon
|
||||
* typemap based on %cstring_mutable but with substantial modifications
|
||||
*/
|
||||
%typemap(in,numinputs=1,fragment="SWIG_AsCharPtrAndSize") (char *con, char **mode) ($*2_ltype temp_mode = 0) {
|
||||
int alloc_status = 0;
|
||||
$1_ltype con_ptr = NULL;
|
||||
size_t con_len = 0;
|
||||
int char_ptr_res = SWIG_AsCharPtrAndSize($input, &con_ptr, &con_len, &alloc_status);
|
||||
if (!SWIG_IsOK(char_ptr_res)) {
|
||||
%argument_fail(char_ptr_res, "char *con", $symname, $argnum);
|
||||
}
|
||||
if (alloc_status != SWIG_NEWOBJ) {
|
||||
// Unconditionally copy because the C function modifies the string in place
|
||||
$1 = %new_copy_array(con_ptr, con_len+1, char);
|
||||
} else {
|
||||
$1 = con_ptr;
|
||||
}
|
||||
|
||||
$2 = &temp_mode;
|
||||
}
|
||||
%typemap(freearg,noblock=1,match="in") (char *con, char **mode) {
|
||||
%delete_array($1);
|
||||
}
|
||||
%typemap(argout,noblock=1,fragment="SWIG_FromCharPtr") (char *con, char **mode) {
|
||||
/*
|
||||
* aa_splitcon returns either con or NULL so we don't need to explicitly
|
||||
* append it to the output, and we don't need the ISVOID helper here
|
||||
*
|
||||
* SWIG_FromCharPtr does NULL checks for us
|
||||
*/
|
||||
%append_output(SWIG_FromCharPtr(*$2));
|
||||
}
|
||||
|
||||
%exception aa_splitcon {
|
||||
$action
|
||||
if (result == NULL) {
|
||||
SWIG_exception_fail(SWIG_ValueError, "received invalid confinement context");
|
||||
}
|
||||
}
|
||||
|
||||
extern char *aa_splitcon(char *con, char **mode);
|
||||
|
||||
/* apparmor_private.h */
|
||||
|
||||
extern int _aa_is_blacklisted(const char *name);
|
||||
|
||||
#ifdef SWIGPYTHON
|
||||
%exception {
|
||||
$action
|
||||
if (result < 0) {
|
||||
// Unfortunately SWIG_exception does not support OSError
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
SWIG_fail;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -187,248 +41,33 @@ extern char *aa_splitcon(char *con, char **mode);
|
||||
|
||||
/* apparmor.h */
|
||||
|
||||
/*
|
||||
* aa_is_enabled returns a boolean as an int with failure reason in errno
|
||||
* Therefore, aa_is_enabled either returns True or throws an exception
|
||||
*
|
||||
* Keep that behavior for backwards compatibilty but return a boolean on Python
|
||||
* where it makes more sense, which isn't a breaking change because a boolean is
|
||||
* a subclass of int
|
||||
*/
|
||||
#ifdef SWIGPYTHON
|
||||
%typemap(out) int {
|
||||
$result = PyBool_FromLong($1);
|
||||
}
|
||||
#endif
|
||||
extern int aa_is_enabled(void);
|
||||
|
||||
#ifdef SWIGPYTHON
|
||||
// Based on SWIG's argcargv.i but we don't have an argc
|
||||
%typemap(in,fragment="SWIG_AsCharPtr") const char *subprofiles[] (Py_ssize_t seq_len=0, int* alloc_tracking = NULL) {
|
||||
void* arg_as_ptr = NULL;
|
||||
int res_convertptr = SWIG_ConvertPtr($input, &arg_as_ptr, $descriptor(char*[]), 0);
|
||||
if (SWIG_IsOK(res_convertptr)) {
|
||||
$1 = %static_cast(arg_as_ptr, $1_ltype);
|
||||
} else {
|
||||
// Clear error that would be set if ptr conversion failed
|
||||
PyErr_Clear();
|
||||
|
||||
int is_list = PyList_Check($input);
|
||||
if (is_list || PyTuple_Check($input)) {
|
||||
seq_len = PySequence_Length($input);
|
||||
/*
|
||||
* %new_array zero-inits for cleaner error handling and memory cleanup
|
||||
* %delete_array(NULL) is no-op (either free or delete), and
|
||||
* alloc_tracking of 0 is uninit
|
||||
*
|
||||
* Further note: SWIG_exception_fail jumps to the freearg typemap
|
||||
*/
|
||||
$1 = %new_array(seq_len+1, char *);
|
||||
if ($1 == NULL) {
|
||||
SWIG_exception_fail(SWIG_MemoryError, "could not allocate C subprofiles");
|
||||
}
|
||||
|
||||
alloc_tracking = %new_array(seq_len, int);
|
||||
if (alloc_tracking == NULL) {
|
||||
SWIG_exception_fail(SWIG_MemoryError, "could not allocate C alloc track arr");
|
||||
}
|
||||
for (Py_ssize_t i=0; i<seq_len; i++) {
|
||||
PyObject *o = is_list ? PyList_GetItem($input, i) : PyTuple_GetItem($input, i);
|
||||
if (o == NULL) {
|
||||
// Failed to get item-Python already set exception info
|
||||
SWIG_fail;
|
||||
} else if (o == Py_None) {
|
||||
// SWIG_AsCharPtr(Py_None, ...) succeeds with ptr output being NULL
|
||||
SWIG_exception_fail(SWIG_ValueError, "sequence contains a None object");
|
||||
}
|
||||
int res = SWIG_AsCharPtr(o, &$1[i], &alloc_tracking[i]);
|
||||
if (!SWIG_IsOK(res)) {
|
||||
// Could emit idx of error here, maybe?
|
||||
SWIG_exception_fail(SWIG_ArgError(res), "sequence does not contain all strings");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SWIG_exception_fail(SWIG_TypeError, "subprofiles is not a list or tuple");
|
||||
}
|
||||
}
|
||||
}
|
||||
%typemap(freearg,noblock=1) const char *subprofiles[] {
|
||||
/*
|
||||
* If static_assert is present, use it to verify the assumption that
|
||||
* allocation uninitialized (0) != SWIG_NEWOBJ
|
||||
*/
|
||||
%#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
/*
|
||||
* Some older versions of SWIG place this right after a goto label
|
||||
* This would then be a label followed by a declaration, a C23 extension (!)
|
||||
* To ensure this works for older SWIG versions and older compilers,
|
||||
* make this a block element with curly braces.
|
||||
*/
|
||||
{static_assert(SWIG_NEWOBJ != 0, "SWIG_NEWOBJ is 0");}
|
||||
%#endif
|
||||
if ($1 != NULL && alloc_tracking$argnum != NULL) {
|
||||
for (Py_ssize_t i=0; i<seq_len$argnum; i++) {
|
||||
if (alloc_tracking$argnum[i] == SWIG_NEWOBJ) {
|
||||
%delete_array($1[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
%delete_array(alloc_tracking$argnum);
|
||||
%delete_array($1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SWIGPERL
|
||||
// Copied from perl's argcargv.i, which should be good enough for us
|
||||
%typemap(in) (const char *subprofiles[]) {
|
||||
int i;
|
||||
SSize_t len;
|
||||
AV *av = (AV *)SvRV($input);
|
||||
if (SvTYPE(av) != SVt_PVAV) {
|
||||
SWIG_croak("in method '$symname', Expecting reference to argv array");
|
||||
goto fail;
|
||||
}
|
||||
len = av_len(av) + 1;
|
||||
$1 = (char **) malloc((len+1)*sizeof(char *));
|
||||
for (i = 0; i < len; i++) {
|
||||
SV **tv = av_fetch(av, i, 0);
|
||||
$1[i] = SvPV_nolen(*tv);
|
||||
}
|
||||
$1[i] = NULL;
|
||||
}
|
||||
|
||||
%typemap(typecheck, precedence=SWIG_TYPECHECK_STRING_ARRAY) (const char *subprofiles[]) {
|
||||
AV *av = (AV *)SvRV($input);
|
||||
$1 = SvTYPE(av) == SVt_PVAV;
|
||||
}
|
||||
|
||||
%typemap(freearg) (const char *subprofiles[]) {
|
||||
free((void *)$1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* These should not receive the VOID_Object typemap */
|
||||
extern int aa_find_mountpoint(char **mnt);
|
||||
extern int aa_change_hat(const char *subprofile, unsigned long magic_token);
|
||||
extern int aa_change_profile(const char *profile);
|
||||
extern int aa_change_onexec(const char *profile);
|
||||
extern int aa_change_hatv(const char *subprofiles[], unsigned long token);
|
||||
extern int aa_change_hat_vargs(unsigned long token, int count, ...);
|
||||
extern int aa_stack_profile(const char *profile);
|
||||
extern int aa_stack_onexec(const char *profile);
|
||||
|
||||
/*
|
||||
* aa_find_mountpoint mnt is an output pointer to a heap-allocated string
|
||||
*
|
||||
* This is a replica of %cstring_output_allocate(char **mnt, free(*$1))
|
||||
* that uses the ISVOID helper to work correctly on SWIG 4.3 or later.
|
||||
*/
|
||||
%typemap(in,noblock=1,numinputs=0) (char **mnt) ($*1_ltype temp_mnt = 0) {
|
||||
$1 = &temp_mnt;
|
||||
}
|
||||
%typemap(freearg,match="in") (char **mnt) ""
|
||||
%typemap(argout,noblock=1,fragment="SWIG_FromCharPtr") (char **mnt) {
|
||||
ISVOID_APPEND_OUTPUT(SWIG_FromCharPtr(*$1));
|
||||
free(*$1);
|
||||
}
|
||||
/* The other errno-based functions should not always be returning the int value:
|
||||
* - Python exceptions signal success/failure status instead via the %exception
|
||||
* handler above.
|
||||
* - Perl (the other binding) has $! for accessing errno but would check the int
|
||||
* return status first.
|
||||
*
|
||||
* The generated C code for (out) resets the return value to None
|
||||
* before appending the returned data (argout generated by %cstring stuff)
|
||||
*/
|
||||
#ifdef SWIGPYTHON
|
||||
%typemap(out,noblock=1) int {
|
||||
#if defined(VOID_Object)
|
||||
$result = VOID_Object;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We can't use "typedef int pid_t" because we still support systems
|
||||
* with 16-bit PIDs and SWIG can't find sys/types.h
|
||||
*
|
||||
* Capture the passed-in value as a long because pid_t is guaranteed
|
||||
* to be a signed integer and because the aalogparse struct uses
|
||||
* (unsigned) longs to store pid values. While intmax_t would be more
|
||||
* technically correct, if sizeof(pid_t) > sizeof(long) then aalogparse
|
||||
* itself would also need fixing.
|
||||
*/
|
||||
%typemap(in,noblock=1,fragment="SWIG_AsVal_long") pid_t (int conv_pid, long pid_large) {
|
||||
%#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
static_assert(sizeof(pid_t) <= sizeof(long),
|
||||
"pid_t type is too large to be stored in a long");
|
||||
%#endif
|
||||
conv_pid = SWIG_AsVal_long($input, &pid_large);
|
||||
if (!SWIG_IsOK(conv_pid)) {
|
||||
%argument_fail(conv_pid, "pid_t", $symname, $argnum);
|
||||
}
|
||||
/*
|
||||
* Cast the long to a pid_t and then cast back to check for overflow
|
||||
* Technically this is implementation-defined behaviour but we should be fine
|
||||
*/
|
||||
$1 = (pid_t) pid_large;
|
||||
if ((long) $1 != pid_large) {
|
||||
SWIG_exception_fail(SWIG_OverflowError, "pid_t is too large");
|
||||
}
|
||||
}
|
||||
|
||||
extern int aa_find_mountpoint(char **mnt);
|
||||
extern int aa_getprocattr(pid_t tid, const char *attr, char **label, char **mode);
|
||||
extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
||||
char **mode);
|
||||
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, socklen_t *len, char **mode);
|
||||
extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
|
||||
/*
|
||||
* Typemaps for the boolean outputs of the query functions
|
||||
* Use boolean types for Python and int types elsewhere
|
||||
*/
|
||||
#ifdef SWIGPYTHON
|
||||
// TODO: find a way to deduplicate these
|
||||
%typemap(in, numinputs=0) int *allowed (int temp) {
|
||||
$1 = &temp;
|
||||
}
|
||||
%typemap(argout) int *allowed {
|
||||
ISVOID_APPEND_OUTPUT(PyBool_FromLong(*$1));
|
||||
}
|
||||
|
||||
%typemap(in, numinputs=0) int *audited (int temp) {
|
||||
$1 = &temp;
|
||||
}
|
||||
%typemap(argout) int *audited {
|
||||
ISVOID_APPEND_OUTPUT(PyBool_FromLong(*$1));
|
||||
}
|
||||
#else
|
||||
%apply int *OUTPUT { int *allowed };
|
||||
%apply int *OUTPUT { int *audited };
|
||||
#endif
|
||||
|
||||
/* Sync this with the apparmor.h */
|
||||
/* Permission flags for the AA_CLASS_FILE mediation class */
|
||||
#define AA_MAY_EXEC (1 << 0)
|
||||
#define AA_MAY_WRITE (1 << 1)
|
||||
#define AA_MAY_READ (1 << 2)
|
||||
#define AA_MAY_APPEND (1 << 3)
|
||||
#define AA_MAY_CREATE (1 << 4)
|
||||
#define AA_MAY_DELETE (1 << 5)
|
||||
#define AA_MAY_OPEN (1 << 6)
|
||||
#define AA_MAY_RENAME (1 << 7)
|
||||
#define AA_MAY_SETATTR (1 << 8)
|
||||
#define AA_MAY_GETATTR (1 << 9)
|
||||
#define AA_MAY_SETCRED (1 << 10)
|
||||
#define AA_MAY_GETCRED (1 << 11)
|
||||
#define AA_MAY_CHMOD (1 << 12)
|
||||
#define AA_MAY_CHOWN (1 << 13)
|
||||
#define AA_MAY_LOCK 0x8000
|
||||
#define AA_EXEC_MMAP 0x10000
|
||||
#define AA_MAY_LINK 0x40000
|
||||
#define AA_MAY_ONEXEC 0x20000000
|
||||
#define AA_MAY_CHANGE_PROFILE 0x40000000
|
||||
|
||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||
int *audit);
|
||||
extern int aa_query_file_path_len(uint32_t mask, const char *label,
|
||||
size_t label_len, const char *path,
|
||||
size_t path_len, int *allowed, int *audited);
|
||||
extern int aa_query_file_path(uint32_t mask, const char *label,
|
||||
const char *path, int *allowed, int *audited);
|
||||
extern int aa_query_link_path_len(const char *label, size_t label_len,
|
||||
const char *target, size_t target_len,
|
||||
const char *link, size_t link_len,
|
||||
int *allowed, int *audited);
|
||||
extern int aa_query_link_path(const char *label, const char *target,
|
||||
const char *link, int *allowed, int *audited);
|
||||
|
||||
|
21
libraries/libapparmor/swig/java/Makefile.am
Normal file
21
libraries/libapparmor/swig/java/Makefile.am
Normal file
@@ -0,0 +1,21 @@
|
||||
WRAPPERFILES = apparmorlogparse_wrap.c
|
||||
|
||||
BUILT_SOURCES = apparmorlogparse_wrap.c
|
||||
|
||||
all-local: apparmorlogparse_wrap.o
|
||||
$(CC) -module apparmorlogparse_wrap.o -o libaalogparse.so
|
||||
|
||||
apparmorlogparse_wrap.o: apparmorlogparse_wrap.c
|
||||
$(CC) -c apparmorlogparse_wrap.c $(CFLAGS) -I../../src -I/usr/include/classpath -fno-strict-aliasing -o apparmorlogparse_wrap.o
|
||||
|
||||
clean-local:
|
||||
rm -rf org
|
||||
|
||||
apparmorlogparse_wrap.c: org/aalogparse ../SWIG/*.i
|
||||
$(SWIG) -java -I../SWIG -I../../src -outdir org/aalogparse \
|
||||
-package org.aalogparse -o apparmorlogparse_wrap.c libaalogparse.i
|
||||
|
||||
org/aalogparse:
|
||||
mkdir -p org/aalogparse
|
||||
|
||||
EXTRA_DIST = $(BUILT_SOURCES)
|
@@ -15,7 +15,6 @@ PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) buildpath.py)'
|
||||
TESTS = test_python.py
|
||||
TESTS_ENVIRONMENT = \
|
||||
LD_LIBRARY_PATH='$(top_builddir)/src/.libs:$(PYTHON_DIST_BUILD_PATH)' \
|
||||
PYTHONPATH='$(PYTHON_DIST_BUILD_PATH)' \
|
||||
PYTHONDONTWRITEBYTECODE='1'
|
||||
PYTHONPATH='$(PYTHON_DIST_BUILD_PATH)'
|
||||
|
||||
endif
|
||||
|
@@ -55,100 +55,10 @@ NO_VALUE_MAP = {
|
||||
'fsuid': int(ctypes.c_ulong(-1).value),
|
||||
'ouid': int(ctypes.c_ulong(-1).value),
|
||||
}
|
||||
|
||||
|
||||
class AAPythonBindingsTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# REPORT ALL THE OUTPUT
|
||||
self.maxDiff = None
|
||||
|
||||
def test_aa_splitcon(self):
|
||||
AA_SPLITCON_EXPECT = [
|
||||
("unconfined", "unconfined", None),
|
||||
("unconfined\n", "unconfined", None),
|
||||
("/bin/ping (enforce)", "/bin/ping", "enforce"),
|
||||
("/bin/ping (enforce)\n", "/bin/ping", "enforce"),
|
||||
("/usr/sbin/rsyslog (complain)", "/usr/sbin/rsyslog", "complain"),
|
||||
]
|
||||
for context, expected_label, expected_mode in AA_SPLITCON_EXPECT:
|
||||
actual_label, actual_mode = libapparmor.aa_splitcon(context)
|
||||
if expected_label is None:
|
||||
self.assertIsNone(actual_label)
|
||||
else:
|
||||
self.assertIsInstance(actual_label, str)
|
||||
self.assertEqual(expected_label, actual_label)
|
||||
|
||||
if expected_mode is None:
|
||||
self.assertIsNone(actual_mode)
|
||||
else:
|
||||
self.assertIsInstance(actual_mode, str)
|
||||
self.assertEqual(expected_mode, actual_mode)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
libapparmor.aa_splitcon("")
|
||||
|
||||
def test_aa_is_enabled(self):
|
||||
aa_enabled = libapparmor.aa_is_enabled()
|
||||
self.assertIsInstance(aa_enabled, bool)
|
||||
|
||||
@unittest.skipUnless(libapparmor.aa_is_enabled(), "AppArmor is not enabled")
|
||||
def test_aa_find_mountpoint(self):
|
||||
mount_point = libapparmor.aa_find_mountpoint()
|
||||
self.assertIsInstance(mount_point, str)
|
||||
self.assertGreater(len(mount_point), 0, "mount point should not be empty")
|
||||
self.assertTrue(os.path.isdir(mount_point))
|
||||
|
||||
# TODO: test commented out functions (or at least their prototypes)
|
||||
# extern int aa_change_profile(const char *profile);
|
||||
# extern int aa_change_onexec(const char *profile);
|
||||
@unittest.skipUnless(libapparmor.aa_is_enabled(), "AppArmor is not enabled")
|
||||
def test_change_hats(self):
|
||||
# Changing hats will fail because we have no valid hats to change to
|
||||
# However, we still verify that we get an OSError instead of a TypeError
|
||||
with self.assertRaises(OSError):
|
||||
libapparmor.aa_change_hat("nonexistent_profile", 12345678)
|
||||
|
||||
with self.assertRaises(OSError):
|
||||
libapparmor.aa_change_hatv(["nonexistent_1", "nonexistent_2"], 0xabcdef)
|
||||
libapparmor.aa_change_hatv(("nonexistent_1", "nonexistent_2"), 0xabcdef)
|
||||
|
||||
# extern int aa_stack_profile(const char *profile);
|
||||
# extern int aa_stack_onexec(const char *profile);
|
||||
# extern int aa_getprocattr(pid_t tid, const char *attr, char **label, char **mode);
|
||||
# extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
||||
|
||||
@unittest.skipUnless(libapparmor.aa_is_enabled(), "AppArmor is not enabled")
|
||||
def test_aa_gettaskcon(self):
|
||||
# Our test harness should be running us as unconfined
|
||||
# Get our own pid and this should be equivalent to aa_getcon
|
||||
pid = os.getpid()
|
||||
|
||||
label, mode = libapparmor.aa_gettaskcon(pid)
|
||||
self.assertEqual(label, "unconfined", "aa_gettaskcon label should be unconfined")
|
||||
self.assertIsNone(mode, "aa_gettaskcon mode should be unconfined")
|
||||
|
||||
@unittest.skipUnless(libapparmor.aa_is_enabled(), "AppArmor is not enabled")
|
||||
def test_aa_getcon(self):
|
||||
# Our test harness should be running us as unconfined
|
||||
label, mode = libapparmor.aa_getcon()
|
||||
self.assertEqual(label, "unconfined", "aa_getcon label should be unconfined")
|
||||
self.assertIsNone(mode, "aa_getcon mode should be unconfined")
|
||||
|
||||
# extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
|
||||
# extern int aa_query_file_path(uint32_t mask, const char *label,
|
||||
# const char *path, int *allowed, int *audited);
|
||||
@unittest.skipUnless(libapparmor.aa_is_enabled(), "AppArmor is not enabled")
|
||||
def test_aa_query_file_path(self):
|
||||
aa_query_mask = libapparmor.AA_MAY_EXEC | libapparmor.AA_MAY_READ | libapparmor.AA_MAY_WRITE
|
||||
allowed, audited = libapparmor.aa_query_file_path(aa_query_mask, "unconfined", "/tmp/hello")
|
||||
self.assertTrue(allowed)
|
||||
self.assertFalse(audited)
|
||||
# extern int aa_query_link_path(const char *label, const char *target,
|
||||
# const char *link, int *allowed, int *audited);
|
||||
|
||||
|
||||
class AALogParsePythonBindingsTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# REPORT ALL THE OUTPUT
|
||||
self.maxDiff = None
|
||||
@@ -208,9 +118,6 @@ class AALogParsePythonBindingsTests(unittest.TestCase):
|
||||
# FIXME: out files should report log version?
|
||||
# FIXME: or can we just deprecate v1 logs?
|
||||
continue
|
||||
elif key == "thisown":
|
||||
# SWIG generates this key to track memory allocation
|
||||
continue
|
||||
elif key in NO_VALUE_MAP:
|
||||
if NO_VALUE_MAP[key] == value:
|
||||
continue
|
||||
@@ -235,7 +142,7 @@ def main():
|
||||
def stub_test(self, testname=f):
|
||||
self._runtest(testname)
|
||||
stub_test.__doc__ = "test " + f
|
||||
setattr(AALogParsePythonBindingsTests, 'test_' + f, stub_test)
|
||||
setattr(AAPythonBindingsTests, 'test_' + f, stub_test)
|
||||
return unittest.main(verbosity=2)
|
||||
|
||||
|
||||
|
@@ -107,7 +107,7 @@ int print_results(aa_log_record *record)
|
||||
print_string("Name", record->name);
|
||||
print_string("Command", record->comm);
|
||||
print_string("Name2", record->name2);
|
||||
print_string("Namespace", record->aa_namespace);
|
||||
print_string("Namespace", record->namespace);
|
||||
print_string("Attribute", record->attribute);
|
||||
print_long("Task", record->task, 0);
|
||||
print_long("Parent", record->parent, 0);
|
||||
@@ -142,7 +142,7 @@ int print_results(aa_log_record *record)
|
||||
|
||||
print_string("Execpath", record->execpath);
|
||||
|
||||
print_string("Class", record->rule_class);
|
||||
print_string("Class", record->class);
|
||||
|
||||
print_long("Epoch", record->epoch, 0);
|
||||
print_long("Audit subid", (long) record->audit_sub_id, 0);
|
||||
|
@@ -1,4 +1,2 @@
|
||||
profile unconfined {
|
||||
change_profile -> system_tor,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,2 @@
|
||||
/home/cb/bin/hello.sh {
|
||||
/usr/bin/rm mrix,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,2 @@
|
||||
/usr/bin/wireshark {
|
||||
/usr/lib64/wireshark/extcap/androiddump mrix,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/bin/ping {
|
||||
/bin/ping mrix,
|
||||
ping2 ix,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/bin/ping {
|
||||
/bin/ping mrix,
|
||||
/bin/ping ix,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/bin/ping {
|
||||
/bin/ping mrix,
|
||||
/bin/ping ix,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +0,0 @@
|
||||
/home/steve/aa-regression-tests/link {
|
||||
/tmp/sdtest.8236-29816-IN8243/target l,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
2025-01-27T13:01:36.226987+05:30 sec-plucky-amd64 kernel: audit: type=1400 audit(1737963096.225:3240): apparmor="AUDIT" operation="getattr" class="file" profile="/usr/sbin/mosquitto" name="/etc/mosquitto/pwfile" pid=8119 comm="mosquitto" requested_mask="r" fsuid=122 ouid=122
|
@@ -1,15 +0,0 @@
|
||||
START
|
||||
File: testcase36.in
|
||||
Event type: AA_RECORD_AUDIT
|
||||
Audit ID: 1737963096.225:3240
|
||||
Operation: getattr
|
||||
Mask: r
|
||||
fsuid: 122
|
||||
ouid: 122
|
||||
Profile: /usr/sbin/mosquitto
|
||||
Name: /etc/mosquitto/pwfile
|
||||
Command: mosquitto
|
||||
PID: 8119
|
||||
Class: file
|
||||
Epoch: 1737963096
|
||||
Audit subid: 3240
|
@@ -1,4 +0,0 @@
|
||||
/usr/sbin/mosquitto {
|
||||
/etc/mosquitto/pwfile r,
|
||||
|
||||
}
|
@@ -1,4 +1,3 @@
|
||||
/tmp/apparmor-2.8.0/tests/regression/apparmor/dbus_service {
|
||||
dbus send bus=system path=/org/freedesktop/systemd1 interface=org.freedesktop.systemd1.Manager member=LookupDynamicUserByName peer=(label=unconfined),
|
||||
|
||||
dbus send bus=system path=/org/freedesktop/systemd1 interface=org.freedesktop.systemd1.Manager member=LookupDynamicUserByName peer=( name=org.freedesktop.systemd1, label=unconfined),
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 aa-teardown.8 apparmor_xattrs
|
||||
# default behavior changed in version 3.6
|
||||
# parse.error=verbose supported from 3.0 so just test on that
|
||||
# TODO move to autoconf
|
||||
BISON_MAJOR:=$(shell bison --version | ${AWK} '/^bison/ { print ($$NF) }' | ${AWK} -F. '{print $$1 }')
|
||||
BISON_MAJOR:=$(shell bison --version | awk '/^bison/ { print ($$NF) }' | awk -F. '{print $$1 }')
|
||||
USE_PARSE_ERROR:=$(shell test "${BISON_MAJOR}" -ge 3 && echo true)
|
||||
|
||||
YACC := bison
|
||||
@@ -105,12 +105,12 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
parser_alias.c common_optarg.c lib.c network.cc \
|
||||
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
||||
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
||||
mqueue.cc io_uring.cc all_rule.cc cond_expr.cc variable.cc symtab.cc
|
||||
mqueue.cc io_uring.cc all_rule.cc cond_expr.cc
|
||||
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
||||
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
||||
parser_include.h parser_version.h policy_cache.h policydb.h \
|
||||
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
||||
common_flags.h bignum.h all_rule.h cond_expr.h variable.h symtab.h
|
||||
common_flags.h bignum.h all_rule.h cond_expr.h
|
||||
|
||||
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
||||
GENERATED_HDRS = af_names.h generated_af_names.h \
|
||||
@@ -331,13 +331,6 @@ all_rule.o: all_rule.cc $(HDRS)
|
||||
cond_expr.o: cond_expr.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
variable.o: variable.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
symtab.o: symtab.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
|
||||
parser_version.h: Makefile
|
||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||
@mv -f .ver $@
|
||||
@@ -372,9 +365,6 @@ cap_names.h: generated_cap_names.h base_cap_names.h
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: tst_binaries
|
||||
tst_binaries: $(TESTS)
|
||||
|
||||
tst_lib: lib.c parser.h $(filter-out lib.o, ${TEST_OBJECTS})
|
||||
$(CXX) $(TEST_CFLAGS) -o $@ $< $(filter-out $(<:.c=.o), ${TEST_OBJECTS}) $(TEST_LDFLAGS) $(TEST_LDLIBS)
|
||||
tst_%: parser_%.c parser.h $(filter-out parser_%.o, ${TEST_OBJECTS})
|
||||
@@ -382,7 +372,7 @@ tst_%: parser_%.c parser.h $(filter-out parser_%.o, ${TEST_OBJECTS})
|
||||
|
||||
errnos.h:
|
||||
echo '#include <errno.h>' > dump.c
|
||||
$(CC) $(CPPFLAGS) -E -dD dump.c | $(AWK) '/^#define E/ { printf "{ \"%s\", %s },\n", $$2, $$2 }' > errnos.h
|
||||
$(CC) -E -dD dump.c | awk '/^#define E/ { printf "{ \"%s\", %s },\n", $$2, $$2 }' > errnos.h
|
||||
rm -f dump.c
|
||||
|
||||
.SILENT: check
|
||||
|
@@ -53,7 +53,7 @@ public:
|
||||
sock_type_n(-1), proto(NULL), proto_n(0), label(NULL),
|
||||
peer_label(NULL) { }
|
||||
|
||||
~af_rule() override
|
||||
virtual ~af_rule()
|
||||
{
|
||||
free(sock_type);
|
||||
free(proto);
|
||||
@@ -73,12 +73,12 @@ public:
|
||||
virtual bool has_peer_conds(void) { return peer_label ? true : false; }
|
||||
virtual ostream &dump_local(ostream &os);
|
||||
virtual ostream &dump_peer(ostream &os);
|
||||
ostream &dump(ostream &os) override;
|
||||
int expand_variables(void) override;
|
||||
int gen_policy_re(Profile &prof) override = 0;
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof) = 0;
|
||||
|
||||
bool is_mergeable(void) override { return true; }
|
||||
int cmp(rule_t const &rhs) const override
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
|
@@ -30,8 +30,6 @@
|
||||
#include "profile.h"
|
||||
#include "af_unix.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* See unix(7) for autobind address definition */
|
||||
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
|
||||
|
||||
|
@@ -41,13 +41,13 @@ public:
|
||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||
unix_rule(perm32_t perms, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
~unix_rule() override
|
||||
virtual ~unix_rule()
|
||||
{
|
||||
free(addr);
|
||||
free(peer_addr);
|
||||
};
|
||||
|
||||
bool valid_prefix(const prefixes &p, const char *&error) override {
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
// priority is partially supported for unix rules
|
||||
// rules that get downgraded to just network socket
|
||||
// won't support them but the fine grained do.
|
||||
@@ -57,17 +57,17 @@ public:
|
||||
}
|
||||
return true;
|
||||
};
|
||||
bool has_peer_conds(void) override {
|
||||
virtual bool has_peer_conds(void) {
|
||||
return af_rule::has_peer_conds() || peer_addr;
|
||||
}
|
||||
|
||||
ostream &dump_local(ostream &os) override;
|
||||
ostream &dump_peer(ostream &os) override;
|
||||
int expand_variables(void) override;
|
||||
int gen_policy_re(Profile &prof) override;
|
||||
virtual ostream &dump_local(ostream &os);
|
||||
virtual ostream &dump_peer(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
// inherit is_mergable() from af_rule
|
||||
int cmp(rule_t const &rhs) const override
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = af_rule::cmp(rhs);
|
||||
if (res)
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
void warn_once(const char *name) override;
|
||||
virtual void warn_once(const char *name) override;
|
||||
};
|
||||
|
||||
#endif /* __AA_AF_UNIX_H */
|
||||
|
@@ -31,7 +31,7 @@ class all_rule: public prefix_rule_t {
|
||||
public:
|
||||
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
||||
|
||||
bool valid_prefix(const prefixes &p, const char *&error) override {
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.priority != 0) {
|
||||
error = _("priority prefix not allowed on all rules");
|
||||
return false;
|
||||
@@ -43,30 +43,30 @@ public:
|
||||
return true;
|
||||
};
|
||||
|
||||
int expand_variables(void) override
|
||||
int expand_variables(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override {
|
||||
virtual ostream &dump(ostream &os) {
|
||||
prefix_rule_t::dump(os);
|
||||
|
||||
os << "all";
|
||||
|
||||
return os;
|
||||
}
|
||||
bool is_mergeable(void) override { return true; }
|
||||
int cmp(rule_t const &rhs) const override
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
return prefix_rule_t::cmp(rhs);
|
||||
};
|
||||
|
||||
void add_implied_rules(Profile &prof) override;
|
||||
virtual void add_implied_rules(Profile &prof);
|
||||
|
||||
int gen_policy_re(Profile &prof unused) override { return RULE_OK; };
|
||||
virtual int gen_policy_re(Profile &prof unused) { return RULE_OK; };
|
||||
|
||||
protected:
|
||||
void warn_once(const char *name unused, const char *msg unused) override { };
|
||||
void warn_once(const char *name unused) override { };
|
||||
virtual void warn_once(const char *name unused, const char *msg unused) { };
|
||||
virtual void warn_once(const char *name unused) { };
|
||||
};
|
||||
|
||||
#endif /* __AA_ALL_H */
|
||||
|
@@ -80,7 +80,7 @@ B<ALIAS RULE> = 'alias' I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ','
|
||||
|
||||
B<INCLUDE> = ( '#include' | 'include' ) [ 'if exists' ] ( I<ABS PATH> | I<MAGIC PATH> )
|
||||
|
||||
B<ABI> = ( 'abi' ) ( I<ABS PATH> | I<MAGIC PATH> | '<kernel>' | '<default>' ) ','
|
||||
B<ABI> = ( 'abi' ) ( I<ABS PATH> | I<MAGIC PATH> ) ','
|
||||
|
||||
B<ABS PATH> = '"' path '"' (the path is passed to open(2))
|
||||
|
||||
@@ -114,8 +114,7 @@ B<XATTR VALUE FILEGLOB> = I<FILEGLOB>
|
||||
B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of I<PROFILE FLAGS> ')'
|
||||
|
||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
||||
| 'attach_disconnected' | 'attach_disconnected.path='I<ABS PATH> | 'chroot_relative'
|
||||
| 'attach_disconnected.ipc' | 'attach_disconnected.ipc='I<ABS PATH>
|
||||
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
||||
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL> | 'error='I<ERROR CODE>
|
||||
|
||||
B<ERROR CODE> = (case insensitive error code name starting with 'E'; see errno(3))
|
||||
@@ -389,7 +388,7 @@ aa_change_hat(2) can take advantage of subprofiles to run under different
|
||||
confinements, dependent on program logic. Several aa_change_hat(2)-aware
|
||||
applications exist, including an Apache module, mod_apparmor(5); a PAM
|
||||
module, pam_apparmor; and a Tomcat valve, tomcat_apparmor. Applications
|
||||
written or modified to use aa_change_profile(2) transition permanently to the
|
||||
written or modified to use change_profile(2) transition permanently to the
|
||||
specified profile. libvirt is one such application.
|
||||
|
||||
=head2 Profile Head
|
||||
@@ -561,14 +560,6 @@ allowed. Its intent is a debug and policy development tool.
|
||||
attach disconnected objects to the supplied path instead of the root of
|
||||
the namespace.
|
||||
|
||||
=item B<attach_disconnected.ipc> A subset of attach_disconnected, but specific
|
||||
for IPC namespaces. It allows attaching disconnected IPC paths without having
|
||||
to allow attaching all types of files.
|
||||
|
||||
=item B<attach_disconnected.ipc>=I<ABS PATH> Like attach_disconnected.ipc, but
|
||||
attach disconnected posix mqueue to the supplied path instead of the root of
|
||||
the namespace.
|
||||
|
||||
=item B<chroot_relative> This forces file names to be relative to a
|
||||
chroot and behave as if the chroot is a mount namespace.
|
||||
|
||||
@@ -613,7 +604,7 @@ modes:
|
||||
|
||||
=item B<Ux>
|
||||
|
||||
- unconfined execute -- use ld.so(8) secure-execution mode
|
||||
- unconfined execute -- scrub the environment
|
||||
|
||||
=item B<px>
|
||||
|
||||
@@ -621,7 +612,7 @@ modes:
|
||||
|
||||
=item B<Px>
|
||||
|
||||
- discrete profile execute -- use ld.so(8) secure-execution mode
|
||||
- discrete profile execute -- scrub the environment
|
||||
|
||||
=item B<cx>
|
||||
|
||||
@@ -629,7 +620,7 @@ modes:
|
||||
|
||||
=item B<Cx>
|
||||
|
||||
- transition to subprofile on execute -- use ld.so(8) secure-execution mode
|
||||
- transition to subprofile on execute -- scrub the environment
|
||||
|
||||
=item B<ix>
|
||||
|
||||
@@ -641,7 +632,7 @@ modes:
|
||||
|
||||
=item B<Pix>
|
||||
|
||||
- discrete profile execute with inherit fallback -- use ld.so(8) secure-execution mode
|
||||
- discrete profile execute with inherit fallback -- scrub the environment
|
||||
|
||||
=item B<cix>
|
||||
|
||||
@@ -649,7 +640,7 @@ modes:
|
||||
|
||||
=item B<Cix>
|
||||
|
||||
- transition to subprofile on execute with inherit fallback -- use ld.so(8) secure-execution mode
|
||||
- transition to subprofile on execute with inherit fallback -- scrub the environment
|
||||
|
||||
=item B<pux>
|
||||
|
||||
@@ -657,7 +648,7 @@ modes:
|
||||
|
||||
=item B<PUx>
|
||||
|
||||
- discrete profile execute with fallback to unconfined -- use ld.so(8) secure-execution mode
|
||||
- discrete profile execute with fallback to unconfined -- scrub the environment
|
||||
|
||||
=item B<cux>
|
||||
|
||||
@@ -665,7 +656,7 @@ modes:
|
||||
|
||||
=item B<CUx>
|
||||
|
||||
- transition to subprofile on execute with fallback to unconfined -- use ld.so(8) secure-execution mode
|
||||
- transition to subprofile on execute with fallback to unconfined -- scrub the environment
|
||||
|
||||
=item B<deny x>
|
||||
|
||||
@@ -724,20 +715,20 @@ constrained, see the apparmor(7) man page.
|
||||
|
||||
B<WARNING> 'ux' should only be used in very special cases. It enables the
|
||||
designated child processes to be run without any AppArmor protection.
|
||||
'ux' does not use ld.so(8) secure-execution mode to clear variables such as
|
||||
LD_PRELOAD; as a result, the calling domain may have an undue amount of
|
||||
influence over the callee. Use this mode only if the child absolutely must be
|
||||
'ux' does not scrub the environment of variables such as LD_PRELOAD;
|
||||
as a result, the calling domain may have an undue amount of influence
|
||||
over the callee. Use this mode only if the child absolutely must be
|
||||
run unconfined and LD_PRELOAD must be used. Any profile using this mode
|
||||
provides negligible security. Use at your own risk.
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
|
||||
=item B<Ux - unconfined execute -- use ld.so(8) secure-execution mode>
|
||||
=item B<Ux - unconfined execute -- scrub the environment>
|
||||
|
||||
'Ux' allows the named program to run in 'ux' mode, but AppArmor
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to set ld.so(8)
|
||||
secure-execution mode and clear environment variables such as LD_PRELOAD,
|
||||
similar to setuid programs. (See ld.so(8) for more information.)
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to scrub
|
||||
the environment, similar to setuid programs. (See ld.so(8) for some
|
||||
information on setuid/setgid environment scrubbing.)
|
||||
|
||||
B<WARNING> 'Ux' should only be used in very special cases. It enables the
|
||||
designated child processes to be run without any AppArmor protection.
|
||||
@@ -752,18 +743,18 @@ This mode requires that a discrete security profile is defined for a
|
||||
program executed and forces an AppArmor domain transition. If there is
|
||||
no profile defined then the access will be denied.
|
||||
|
||||
B<WARNING> 'px' does not use ld.so(8) secure-execution mode to clear variables
|
||||
such as LD_PRELOAD; as a result, the calling domain may have an undue amount of
|
||||
B<WARNING> 'px' does not scrub the environment of variables such as
|
||||
LD_PRELOAD; as a result, the calling domain may have an undue amount of
|
||||
influence over the callee.
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
|
||||
=item B<Px - Discrete Profile execute mode -- use ld.so(8) secure-execution mode>
|
||||
=item B<Px - Discrete Profile execute mode -- scrub the environment>
|
||||
|
||||
'Px' allows the named program to run in 'px' mode, but AppArmor
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to set ld.so(8)
|
||||
secure-execution mode and clear environment variables such as LD_PRELOAD,
|
||||
similar to setuid programs. (See ld.so(8) for more information.)
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to scrub
|
||||
the environment, similar to setuid programs. (See ld.so(8) for some
|
||||
information on setuid/setgid environment scrubbing.)
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
|
||||
@@ -773,18 +764,18 @@ This mode requires that a local security profile is defined and forces an
|
||||
AppArmor domain transition to the named profile. If there is no profile
|
||||
defined then the access will be denied.
|
||||
|
||||
B<WARNING> 'cx' does not use ld.so(8) secure-execution mode to clear variables
|
||||
such as LD_PRELOAD; as a result, the calling domain may have an undue amount of
|
||||
B<WARNING> 'cx' does not scrub the environment of variables such as
|
||||
LD_PRELOAD; as a result, the calling domain may have an undue amount of
|
||||
influence over the callee.
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
|
||||
=item B<Cx - Transition to Subprofile execute mode -- use ld.so(8) secure-execution mode>
|
||||
=item B<Cx - Transition to Subprofile execute mode -- scrub the environment>
|
||||
|
||||
'Cx' allows the named program to run in 'cx' mode, but AppArmor
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to set ld.so(8)
|
||||
secure-execution mode and clear environment variables such as LD_PRELOAD,
|
||||
similar to setuid programs. (See ld.so(8) for more information.)
|
||||
will invoke the Linux Kernel's B<unsafe_exec> routines to scrub
|
||||
the environment, similar to setuid programs. (See ld.so(8) for some
|
||||
information on setuid/setgid environment scrubbing.)
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
|
||||
@@ -797,7 +788,7 @@ will inherit the current profile.
|
||||
This mode is useful when a confined program needs to call another
|
||||
confined program without gaining the permissions of the target's
|
||||
profile, or losing the permissions of the current profile. There is no
|
||||
version to set secure-execution mode because 'ix' executions don't change
|
||||
version to scrub the environment because 'ix' executions don't change
|
||||
privileges.
|
||||
|
||||
Incompatible with other exec transition modes and the deny qualifier.
|
||||
@@ -1033,7 +1024,7 @@ If a conditional is specified using '=', then the rule only grants permission
|
||||
for mounts matching the exactly specified options. For example, an AppArmor
|
||||
policy with the following rule:
|
||||
|
||||
mount options=ro /dev/foo -> /mnt/,
|
||||
mount options=ro /dev/foo -E<gt> /mnt/,
|
||||
|
||||
Would match:
|
||||
|
||||
@@ -1080,7 +1071,7 @@ grants permission for each set of options. This provides a shorthand when
|
||||
writing mount rules which might help to logically break up a conditional. For
|
||||
example, if an AppArmor policy has the following rule:
|
||||
|
||||
mount options=ro options=atime,
|
||||
mount options=ro options=atime
|
||||
|
||||
both of these mount commands will match:
|
||||
|
||||
@@ -1196,17 +1187,17 @@ using inode access times. Matches only:
|
||||
|
||||
=item B<< mount options=(ro, atime) options in (nodev, user) /dev/foo -E<gt> /mnt/, >>
|
||||
|
||||
allow mounting /dev/foo on /mnt/ read only and using inode access times, in
|
||||
addition to allowing some combination of 'nodev' and 'user' to be added on top.
|
||||
allow mounting /dev/foo on /mmt/ read only and using inode access times or
|
||||
allow mounting /dev/foo on /mnt/ with some combination of 'nodev' and 'user'.
|
||||
Matches only:
|
||||
|
||||
$ mount -o ro,atime /dev/foo /mnt
|
||||
|
||||
$ mount -o ro,atime,nodev /dev/foo /mnt
|
||||
$ mount -o nodev /dev/foo /mnt
|
||||
|
||||
$ mount -o ro,atime,user /dev/foo /mnt
|
||||
$ mount -o user /dev/foo /mnt
|
||||
|
||||
$ mount -o ro,atime,nodev,user /dev/foo /mnt
|
||||
$ mount -o nodev,user /dev/foo /mnt
|
||||
|
||||
=back
|
||||
|
||||
@@ -1328,7 +1319,7 @@ Example IO_URING rules:
|
||||
=over 4
|
||||
|
||||
# Allow io_uring operations
|
||||
io_uring,
|
||||
io_ring,
|
||||
|
||||
# Allow creation of a polling thread
|
||||
io_uring sqpoll,
|
||||
@@ -1348,9 +1339,8 @@ pivot_root(2) is optionally specified in the 'pivot_root' rule using the
|
||||
'oldroot=' prefix.
|
||||
|
||||
AppArmor 'pivot_root' rules can specify a profile transition to occur during
|
||||
the pivot_root(2) system call. Note that currently, this feature is not
|
||||
supported by any kernel. When this feature will be supported, AppArmor will
|
||||
only transition the process calling pivot_root(2) to the new profile.
|
||||
the pivot_root(2) system call. Note that AppArmor will only transition the
|
||||
process calling pivot_root(2) to the new profile.
|
||||
|
||||
The paths specified in 'pivot_root' rules must end with '/' since they are
|
||||
directories.
|
||||
@@ -1699,11 +1689,11 @@ rule set. Eg.
|
||||
change_profile /bin/bash -> {new_profile1,new_profile2,new_profile3},
|
||||
|
||||
The exec mode dictates whether or not the Linux Kernel's B<unsafe_exec>
|
||||
routines should be used to set ld.so(8) secure-execution mode and clear
|
||||
environment variables such as LD_PRELOAD, similar to setuid programs.
|
||||
(See ld.so(8) for more information.) The B<safe> mode sets up secure-execution
|
||||
mode for the new application, and B<unsafe> mode disables AppArmor's
|
||||
requirement for it (the kernel and/or libc may still turn it on). An
|
||||
routines should be used to scrub the environment, similar to setuid programs.
|
||||
(See ld.so(8) for some information on setuid/setgid environment scrubbing.) The
|
||||
B<safe> mode sets up environment scrubbing to occur when the new application is
|
||||
executed and B<unsafe> mode disables AppArmor's requirement for environment
|
||||
scrubbing (the kernel and/or libc may still require environment scrubbing). An
|
||||
exec mode can only be specified when an exec condition is present.
|
||||
|
||||
change_profile safe /bin/bash -> new_profile,
|
||||
@@ -1802,84 +1792,8 @@ site-specific customization of B<@{HOMEDIRS}>,
|
||||
F</etc/apparmor.d/tunables/multiarch.d> for B<@{multiarch}> and
|
||||
F</etc/apparmor.d/tunables/xdg-user-dirs.d> for B<@{XDG_*}>.
|
||||
|
||||
=head3 Special builtin variables
|
||||
|
||||
AppArmor has some builtin variables that are not declared in policy
|
||||
but are available to be used in policy.
|
||||
|
||||
@{profile_name} - the profile name
|
||||
@{attach_path} - the profile exec attachment path - if one has been defined
|
||||
@{exec_path} - the executables path
|
||||
|
||||
|
||||
The B<@{profile_name}> variable is set to the profile name and may be
|
||||
used in all policy. It is only defined when used inside of a profile.
|
||||
|
||||
The B<@{attach_path}> variable is only defined if the profile will attach
|
||||
to an executable. It will be the path attachment specification or
|
||||
if that is not defined it may be the profile's name if the profile name
|
||||
is a path.
|
||||
|
||||
The B<@{exec_path}> variable like B<@{attach_path}> is only defined if
|
||||
the profile attaches to an executable. If the kernel supports it as a
|
||||
kernel variable, it will be set to the specific path that matches the
|
||||
executable at run time. If the kernel does not support kernel variables
|
||||
it will have the same value as B<@{attach_path}>.
|
||||
|
||||
=head3 Notes on variable expansion and the / character
|
||||
|
||||
It is important to note that how AppArmor performs variable expansion
|
||||
depends on the context where a variable is used. When a variable is
|
||||
expanded it can result in a string with multiple path characters
|
||||
next to each other, in a way that is not evident when looking at
|
||||
policy.
|
||||
|
||||
Eg.
|
||||
|
||||
=over 4
|
||||
|
||||
Given the following variable definition and rule
|
||||
|
||||
@{HOME}=/home/*/
|
||||
file rw @{HOME}/*,
|
||||
|
||||
The variable expansion results in a rule of
|
||||
|
||||
file rw /home/*//*.
|
||||
|
||||
=back
|
||||
|
||||
When this occurs in a context where a path is expected, AppArmor will
|
||||
canonicalize the path by collapsing consecutive / characters into
|
||||
a single character. For the above example, this would be
|
||||
|
||||
file rw /home/*/*,
|
||||
|
||||
There is one exception to this rule, when the consecutive / characters
|
||||
are at the beginning of a path, this indicates a posix namespace
|
||||
and the characters will not be collapsed.
|
||||
|
||||
Eg.
|
||||
|
||||
=over 4
|
||||
|
||||
@{HOME}=/home/*/
|
||||
file rw /@{HOME}/*,
|
||||
|
||||
will result in an expansion of
|
||||
|
||||
file rw //home/*//*,
|
||||
|
||||
which is collapsed to
|
||||
|
||||
file rw //home/*/*,
|
||||
|
||||
Note: that the leading // in the above example is not collapsed to a
|
||||
single /. However the second // (that was also seen in the first
|
||||
example) is collapsed.
|
||||
|
||||
=back
|
||||
|
||||
The special B<@{profile_name}> variable is set to the profile name and may be
|
||||
used in all policy.
|
||||
|
||||
=head2 Alias rules
|
||||
|
||||
@@ -2148,8 +2062,6 @@ If the policy abi is specified as B<kernel> then the running kernel's
|
||||
abi will be used. This should never be used in shipped policy as it
|
||||
can cause system breakage when a new kernel is installed.
|
||||
|
||||
The special abi B<default> is equivalent to not specifying an ABI.
|
||||
|
||||
=head3 ABI compatibility with AppArmor 2.x
|
||||
|
||||
AppArmor 3 remains compatible with AppArmor 2.x by detecting when a
|
||||
@@ -2182,8 +2094,9 @@ An example AppArmor profile:
|
||||
/lib/lib*.so* r,
|
||||
/proc/[0-9]** r,
|
||||
/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.
|
||||
@@ -2245,7 +2158,7 @@ negative values match when specifying one or the other. Eg, 'rw' matches when
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor_parser(8), apparmor_xattrs(7), aa-complain(1),
|
||||
aa-enforce(1), aa_change_hat(2), aa_change_profile(2), mod_apparmor(5), and
|
||||
aa-enforce(1), aa_change_hat(2), mod_apparmor(5), and
|
||||
L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -206,8 +206,8 @@ which can help debugging profiles.
|
||||
=head2 Enable debug mode
|
||||
|
||||
When debug mode is enabled, AppArmor will log a few extra messages to
|
||||
dmesg (not via the audit subsystem). For example, the logs will state when
|
||||
ld.so(8) secure-execution mode has been applied in a profile transition.
|
||||
dmesg (not via the audit subsystem). For example, the logs will tell
|
||||
whether environment scrubbing has been applied.
|
||||
|
||||
To enable debug mode, run:
|
||||
|
||||
|
@@ -63,6 +63,7 @@ typedef enum capability_flags {
|
||||
} capability_flags;
|
||||
|
||||
int name_to_capability(const char *keyword);
|
||||
void capabilities_init(void);
|
||||
void __debug_capabilities(uint64_t capset, const char *name);
|
||||
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags);
|
||||
void clear_cap_flag(capability_flags flags);
|
||||
|
@@ -44,12 +44,10 @@ optflag_table_t dumpflag_table[] = {
|
||||
DUMP_DFA_PROGRESS | DUMP_DFA_STATS },
|
||||
{ 1, "dfa-stats", "Dump dfa creation stats", DUMP_DFA_STATS },
|
||||
{ 1, "dfa-states", "Dump final dfa state information", DUMP_DFA_STATES },
|
||||
{ 1, "dfa-compressed-states", "Dump compressed dfa state information", DUMP_DFA_COMPTRESSED_STATES },
|
||||
{ 1, "dfa-states-initial", "Dump dfa state immediately after initial build", DUMP_DFA_STATES_INIT },
|
||||
{ 1, "dfa-states-post-filter", "Dump dfa state immediately after filtering deny", DUMP_DFA_STATES_POST_FILTER },
|
||||
{ 1, "dfa-states-post-minimize", "Dump dfa state immediately after initial build", DUMP_DFA_STATES_POST_MINIMIZE },
|
||||
{ 1, "dfa-states-post-unreachable", "Dump dfa state immediately after filtering deny", DUMP_DFA_STATES_POST_UNREACHABLE },
|
||||
{ 1, "dfa-perms-build", "Dump permission being built from accept node", DUMP_DFA_PERMS },
|
||||
{ 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DUMP_DFA_GRAPH },
|
||||
{ 1, "dfa-minimize", "Dump dfa minimization", DUMP_DFA_MINIMIZE },
|
||||
{ 1, "dfa-unreachable", "Dump dfa unreachable states",
|
||||
|
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "cond_expr.h"
|
||||
#include "parser.h"
|
||||
#include "symtab.h"
|
||||
|
||||
cond_expr::cond_expr(bool result):
|
||||
result(result)
|
||||
@@ -27,21 +26,20 @@ cond_expr::cond_expr(bool result):
|
||||
|
||||
cond_expr::cond_expr(const char *var, bool defined)
|
||||
{
|
||||
variable *ref;
|
||||
char *var_name = process_var(var);
|
||||
|
||||
if (!defined) {
|
||||
ref = symtab::get_boolean_var(var);
|
||||
if (!ref) {
|
||||
int ret = get_boolean_var(var_name);
|
||||
if (ret < 0) {
|
||||
/* FIXME check for set var */
|
||||
free(var_name);
|
||||
yyerror(_("Unset boolean variable %s used in if-expression"), var);
|
||||
}
|
||||
result = ref->boolean;
|
||||
result = ret;
|
||||
} else {
|
||||
ref = symtab::get_set_var(var);
|
||||
if (!ref) {
|
||||
result = false;
|
||||
} else {
|
||||
PDEBUG("Matched: defined set expr %s value %s\n", var, ref->expanded.begin()->c_str());
|
||||
result = true;
|
||||
}
|
||||
void *set_value = get_set_var(var_name);
|
||||
PDEBUG("Matched: defined set expr %s value %lx\n", var_name, (long) set_value);
|
||||
result = !! (long) set_value;
|
||||
}
|
||||
free(var_name);
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
dbus_rule(perm32_t perms_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
~dbus_rule() override {
|
||||
virtual ~dbus_rule() {
|
||||
free(bus);
|
||||
free(name);
|
||||
free(peer_label);
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
free(interface);
|
||||
free(member);
|
||||
};
|
||||
bool valid_prefix(const prefixes &p, const char *&error) override {
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner != OWNER_UNSPECIFIED) {
|
||||
error = "owner prefix not allowed on dbus rules";
|
||||
return false;
|
||||
@@ -58,12 +58,12 @@ public:
|
||||
return true;
|
||||
};
|
||||
|
||||
ostream &dump(ostream &os) override;
|
||||
int expand_variables(void) override;
|
||||
int gen_policy_re(Profile &prof) override;
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
bool is_mergeable(void) override { return true; }
|
||||
int cmp(rule_t const &rhs) const override
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
|
||||
protected:
|
||||
void warn_once(const char *name) override;
|
||||
virtual void warn_once(const char *name) override;
|
||||
};
|
||||
|
||||
#endif /* __AA_DBUS_H */
|
||||
|
@@ -21,12 +21,14 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* TODO: have includecache be a frontend for file cache, don't just
|
||||
* store name.
|
||||
*/
|
||||
class IncludeCache_t {
|
||||
public:
|
||||
std::set<std::string> cache;
|
||||
set<string> cache;
|
||||
|
||||
IncludeCache_t() = default;
|
||||
virtual ~IncludeCache_t() = default;
|
||||
@@ -37,7 +39,7 @@ public:
|
||||
}
|
||||
|
||||
bool insert(const char *name) {
|
||||
std::pair<std::set<std::string>::iterator,bool> res = cache.insert(name);
|
||||
pair<set<string>::iterator,bool> res = cache.insert(name);
|
||||
if (res.second == false) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -95,12 +95,6 @@
|
||||
#define ALL_USER_EXEC (AA_USER_EXEC | AA_USER_EXEC_TYPE)
|
||||
#define ALL_OTHER_EXEC (AA_OTHER_EXEC | AA_OTHER_EXEC_TYPE)
|
||||
|
||||
#define AA_USER_EXEC_INHERIT (AA_EXEC_INHERIT << AA_USER_SHIFT)
|
||||
#define AA_OTHER_EXEC_INHERIT (AA_EXEC_INHERIT << AA_OTHER_SHIFT)
|
||||
|
||||
#define AA_USER_EXEC_MMAP (AA_OLD_EXEC_MMAP << AA_USER_SHIFT)
|
||||
#define AA_OTHER_EXEC_MMAP (AA_OLD_EXEC_MMAP << AA_OTHER_SHIFT)
|
||||
|
||||
#define AA_LINK_BITS ((AA_OLD_MAY_LINK << AA_USER_SHIFT) | \
|
||||
(AA_OLD_MAY_LINK << AA_OTHER_SHIFT))
|
||||
|
||||
|
@@ -32,12 +32,12 @@ public:
|
||||
char *label;
|
||||
|
||||
io_uring_rule(perm32_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
|
||||
~io_uring_rule() override
|
||||
virtual ~io_uring_rule()
|
||||
{
|
||||
free(label);
|
||||
};
|
||||
|
||||
bool valid_prefix(const prefixes &p, const char *&error) override {
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on io_uring rules");
|
||||
return false;
|
||||
@@ -45,12 +45,12 @@ public:
|
||||
return true;
|
||||
};
|
||||
|
||||
ostream &dump(ostream &os) override;
|
||||
int expand_variables(void) override;
|
||||
int gen_policy_re(Profile &prof) override;
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
bool is_mergeable(void) override { return true; }
|
||||
int cmp(rule_t const &rhs) const override
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
void warn_once(const char *name) override;
|
||||
virtual void warn_once(const char *name) override;
|
||||
};
|
||||
|
||||
#endif /* __AA_IO_URING_H */
|
||||
|
@@ -28,8 +28,6 @@
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int dirat_for_each(int dirfd, const char *name, void *data,
|
||||
int (* cb)(int, const char *, struct stat *, void *))
|
||||
{
|
||||
|
@@ -10,199 +10,6 @@ aare_rules.{h,cc} - code to that binds parse -> expr-tree -> hfa generation
|
||||
-> chfa generation into a basic interface for converting
|
||||
rules to a runtime ready state machine.
|
||||
|
||||
Notes on the compiler pipeline order
|
||||
============================================
|
||||
|
||||
Front End: Program driver logic and policy text parsing into an
|
||||
abstract syntax tree.
|
||||
Middle Layer: Transforms and operations on the abstract syntax tree.
|
||||
Converts syntax tree into expression tree for back end.
|
||||
Back End: transforms of syntax tree, and creation of policy HFA from
|
||||
expression trees and HFAs.
|
||||
|
||||
|
||||
Basic order of the backend of the compiler pipe line and where the
|
||||
dump information occurs in the pipeline.
|
||||
|
||||
===== Front End (parse -> AST ================
|
||||
|
|
||||
v
|
||||
yyparse
|
||||
|
|
||||
+--->--+-->-+
|
||||
| |
|
||||
| +-->---- +---------------------------<-----------------------+
|
||||
| | | |
|
||||
| | v |
|
||||
| | yylex |
|
||||
| | | |
|
||||
| ^ token match |
|
||||
| | | |
|
||||
| | +----------------------------+ |
|
||||
| | | | ^
|
||||
| | v v |
|
||||
| +-<- rule match? preprocess |
|
||||
| | | |
|
||||
| early var expansion +----------+-----------+ |
|
||||
| | | | | |
|
||||
^ v v v v |
|
||||
| new rule() / new ent include variable conditional |
|
||||
| | | | | |
|
||||
| v +---->-----+----->-----+----->----+
|
||||
| new rule semantic check
|
||||
| |
|
||||
+-----<-----+
|
||||
|
|
||||
----------- | ------ End of Parse --------------------
|
||||
|
|
||||
v
|
||||
post_parse_profile semantic check
|
||||
|
|
||||
v
|
||||
post_process
|
||||
|
|
||||
v
|
||||
add implied rules()
|
||||
|
|
||||
v
|
||||
process_profile_variables()
|
||||
|
|
||||
v
|
||||
rule->expand_variables()
|
||||
|
|
||||
+--------+
|
||||
|
|
||||
v
|
||||
replace aliases (to be moved to backend rewrite)
|
||||
|
|
||||
v
|
||||
merge rules
|
||||
|
|
||||
v
|
||||
profile->merge_rules()
|
||||
|
|
||||
v
|
||||
+-->--rule->is_mergeable()
|
||||
| |
|
||||
^ v
|
||||
| add to table
|
||||
| |
|
||||
+-------+--------+
|
||||
|
|
||||
v
|
||||
sort->cmp()/oper<()
|
||||
|
|
||||
rule->merge()
|
||||
|
|
||||
+------------+
|
||||
|
|
||||
v
|
||||
process_profile_rules
|
||||
|
|
||||
v
|
||||
rule->gen_policy_re()
|
||||
|
|
||||
v
|
||||
===== Mid layer (AST -> expr tree) =================
|
||||
|
|
||||
+-> add_rule() (aare_rules.{h,cc})
|
||||
| |
|
||||
| v
|
||||
| rule parse (parse.y)
|
||||
| | |
|
||||
| | v
|
||||
| | expr tree (expr-tree.{h,cc})
|
||||
| | |
|
||||
| v |
|
||||
| unique perms | (aare_rules.{h,cc})
|
||||
| | |
|
||||
| +------ +
|
||||
| |
|
||||
| v
|
||||
| add to rules expr tree (aare_rules.{h,c})
|
||||
| |
|
||||
+------+
|
||||
|
|
||||
+------------------+
|
||||
|
|
||||
v
|
||||
create_dfablob()
|
||||
|
|
||||
v
|
||||
expr tree
|
||||
|
|
||||
v
|
||||
create_chfa() (aare_rules.cc)
|
||||
|
|
||||
v
|
||||
expr normalization (expr-tree.{h,cc})
|
||||
|
|
||||
v
|
||||
expr simplification (expr-tree.{h,c})
|
||||
|
|
||||
+- D expr-tree
|
||||
|
|
||||
+- D expr-simplified
|
||||
|
|
||||
==== Back End - Create cHFA out of expr tree and other HFAs ====
|
||||
v
|
||||
hfa creation (hfa.{h,cc})
|
||||
|
|
||||
+- D dfa-node-map
|
||||
|
|
||||
+- D dfa-uniq-perms
|
||||
|
|
||||
+- D dfa-states-initial
|
||||
|
|
||||
v
|
||||
hfa rewrite (not yet implemented)
|
||||
|
|
||||
v
|
||||
filter deny (hfa.{h,cc})
|
||||
|
|
||||
+- D dfa-states-post-filter
|
||||
|
|
||||
v
|
||||
minimization (hfa.{h,cc})
|
||||
|
|
||||
+- D dfa-minimize-partitions
|
||||
|
|
||||
+- D dfa-minimize-uniq-perms
|
||||
|
|
||||
+- D dfa-states-post-minimize
|
||||
|
|
||||
v
|
||||
unreachable state removal (hfa.{h,cc})
|
||||
|
|
||||
+- D dfa-states-post-unreachable
|
||||
|
|
||||
+- D dfa-states constructed hfa
|
||||
|
|
||||
+- D dfa-graph
|
||||
|
|
||||
v
|
||||
equivalence class construction
|
||||
|
|
||||
+- D equiv
|
||||
|
|
||||
diff encode (hfa.{h,cc})
|
||||
|
|
||||
+- D diff-encode
|
||||
|
|
||||
compute perms table
|
||||
|
|
||||
+- D compressed-dfa == perm table dump
|
||||
|
|
||||
compressed hfa (chfa.{h,cc}
|
||||
|
|
||||
+- D compressed-dfa == transition tables
|
||||
|
|
||||
+- D dfa-compressed-states - compress HFA in state form
|
||||
|
|
||||
v
|
||||
Return to Mid Layer
|
||||
|
||||
|
||||
Notes on the compress hfa file format (chfa)
|
||||
==============================================
|
||||
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include "chfa.h"
|
||||
#include "../immunix.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
aare_rules::~aare_rules(void)
|
||||
{
|
||||
@@ -203,7 +202,7 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
||||
CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts, bool filedfa,
|
||||
bool extended_perms)
|
||||
bool extended_perms, bool prompt)
|
||||
{
|
||||
/* finish constructing the expr tree from the different permission
|
||||
* set nodes */
|
||||
@@ -260,7 +259,7 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
dfa.dump_uniq_perms("dfa");
|
||||
|
||||
if (opts.dump & DUMP_DFA_STATES_INIT)
|
||||
dfa.dump(cerr, NULL);
|
||||
dfa.dump(cerr);
|
||||
|
||||
/* since we are building a chfa, use the info about
|
||||
* whether the chfa supports extended perms to help
|
||||
@@ -272,23 +271,23 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
((opts.control & CONTROL_DFA_FILTER_DENY))) {
|
||||
dfa.apply_and_clear_deny();
|
||||
if (opts.dump & DUMP_DFA_STATES_POST_FILTER)
|
||||
dfa.dump(cerr, NULL);
|
||||
dfa.dump(cerr);
|
||||
}
|
||||
if (opts.control & CONTROL_DFA_MINIMIZE) {
|
||||
dfa.minimize(opts);
|
||||
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("minimized dfa");
|
||||
if (opts.dump & DUMP_DFA_STATES_POST_MINIMIZE)
|
||||
dfa.dump(cerr, NULL);
|
||||
dfa.dump(cerr);
|
||||
}
|
||||
|
||||
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE) {
|
||||
dfa.remove_unreachable(opts);
|
||||
if (opts.dump & DUMP_DFA_STATES_POST_UNREACHABLE)
|
||||
dfa.dump(cerr, NULL);
|
||||
dfa.dump(cerr);
|
||||
}
|
||||
if (opts.dump & DUMP_DFA_STATES)
|
||||
dfa.dump(cerr, NULL);
|
||||
dfa.dump(cerr);
|
||||
|
||||
if (opts.dump & DUMP_DFA_GRAPH)
|
||||
dfa.dump_dot_graph(cerr);
|
||||
@@ -315,7 +314,7 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
//cerr << "Checking extended perms " << extended_perms << "\n";
|
||||
if (extended_perms) {
|
||||
//cerr << "creating permstable\n";
|
||||
dfa.compute_perms_table(perms_table);
|
||||
dfa.compute_perms_table(perms_table, prompt);
|
||||
// TODO: move perms table to a class
|
||||
if (opts.dump & DUMP_DFA_TRANS_TABLE && perms_table.size()) {
|
||||
cerr << "Perms Table size: " << perms_table.size() << "\n";
|
||||
@@ -329,11 +328,9 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
cerr << "\n";
|
||||
}
|
||||
}
|
||||
chfa = new CHFA(dfa, eq, opts, extended_perms);
|
||||
chfa = new CHFA(dfa, eq, opts, extended_perms, prompt);
|
||||
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
||||
chfa->dump(cerr);
|
||||
if (opts.dump & DUMP_DFA_COMPTRESSED_STATES)
|
||||
dfa.dump(cerr, &chfa->num);
|
||||
}
|
||||
catch(int error) {
|
||||
return NULL;
|
||||
@@ -350,14 +347,15 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
void *aare_rules::create_dfablob(size_t *size, int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts, bool filedfa,
|
||||
bool extended_perms)
|
||||
bool extended_perms, bool prompt)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
stringstream stream;
|
||||
|
||||
try {
|
||||
CHFA *chfa = create_chfa(min_match_len, perms_table,
|
||||
opts, filedfa, extended_perms);
|
||||
opts, filedfa, extended_perms,
|
||||
prompt);
|
||||
if (!chfa) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
@@ -382,3 +380,82 @@ void *aare_rules::create_dfablob(size_t *size, int *min_match_len,
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/* create a dfa from the ruleset
|
||||
* returns: buffer contain dfa tables, @size set to the size of the tables
|
||||
* else NULL on failure, @min_match_len set to the shortest string
|
||||
* that can match the dfa for determining xmatch priority.
|
||||
*/
|
||||
void *aare_rules::create_welded_dfablob(aare_rules *file_rules,
|
||||
size_t *size, int *min_match_len,
|
||||
size_t *new_start,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts,
|
||||
bool extended_perms, bool prompt)
|
||||
{
|
||||
int file_min_len;
|
||||
vector <aa_perms> file_perms;
|
||||
CHFA *file_chfa;
|
||||
try {
|
||||
file_chfa = file_rules->create_chfa(&file_min_len,
|
||||
file_perms, opts,
|
||||
true, extended_perms, prompt);
|
||||
if (!file_chfa) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch(int error) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CHFA *policy_chfa;
|
||||
try {
|
||||
policy_chfa = create_chfa(min_match_len,
|
||||
perms_table, opts,
|
||||
false, extended_perms, prompt);
|
||||
if (!policy_chfa) {
|
||||
delete file_chfa;
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch(int error) {
|
||||
delete file_chfa;
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stringstream stream;
|
||||
try {
|
||||
policy_chfa->weld_file_to_policy(*file_chfa, *new_start,
|
||||
extended_perms, prompt,
|
||||
perms_table, file_perms);
|
||||
policy_chfa->flex_table(stream, opts);
|
||||
}
|
||||
catch(int error) {
|
||||
delete (file_chfa);
|
||||
delete (policy_chfa);
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
delete file_chfa;
|
||||
delete policy_chfa;
|
||||
|
||||
/* write blob to buffer */
|
||||
stringbuf *buf = stream.rdbuf();
|
||||
|
||||
buf->pubseekpos(0);
|
||||
*size = buf->in_avail();
|
||||
if (file_min_len < *min_match_len)
|
||||
*min_match_len = file_min_len;
|
||||
|
||||
char *buffer = (char *)malloc(*size);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
buf->sgetn(buffer, *size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
class UniquePermsCache {
|
||||
public:
|
||||
typedef std::map<UniquePerm, Node*> UniquePermMap;
|
||||
typedef map<UniquePerm, Node*> UniquePermMap;
|
||||
typedef UniquePermMap::iterator iterator;
|
||||
UniquePermMap nodes;
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
node = new ExactMatchFlag(priority, perms, audit);
|
||||
else
|
||||
node = new MatchFlag(priority, perms, audit);
|
||||
std::pair<iterator, bool> val = nodes.insert(std::make_pair(tmp, node));
|
||||
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
|
||||
if (val.second == false) {
|
||||
delete node;
|
||||
return val.first->second;
|
||||
@@ -121,13 +121,19 @@ class aare_rules {
|
||||
optflags const &opts, bool oob);
|
||||
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
|
||||
CHFA *create_chfa(int *min_match_len,
|
||||
std::vector <aa_perms> &perms_table,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts, bool filedfa,
|
||||
bool extended_perms);
|
||||
bool extended_perms, bool prompt);
|
||||
void *create_dfablob(size_t *size, int *min_match_len,
|
||||
std::vector <aa_perms> &perms_table,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts,
|
||||
bool filedfa, bool extended_perms);
|
||||
bool filedfa, bool extended_perms, bool prompt);
|
||||
void *create_welded_dfablob(aare_rules *file_rules,
|
||||
size_t *size, int *min_match_len,
|
||||
size_t *new_start,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts,
|
||||
bool extended_perms, bool prompt);
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_RULES_H */
|
||||
|
@@ -64,7 +64,5 @@
|
||||
#define DUMP_DFA_STATES_POST_FILTER (1 << 26)
|
||||
#define DUMP_DFA_STATES_POST_MINIMIZE (1 << 27)
|
||||
#define DUMP_DFA_STATES_POST_UNREACHABLE (1 << 28)
|
||||
#define DUMP_DFA_COMPTRESSED_STATES (1 << 29)
|
||||
#define DUMP_DFA_PERMS (1 << 30)
|
||||
|
||||
#endif /* APPARMOR_RE_H */
|
||||
|
@@ -25,8 +25,6 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -37,8 +35,6 @@
|
||||
#include "../policydb.h"
|
||||
#include "flex-tables.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
size_t prev, size_t start)
|
||||
{
|
||||
@@ -59,7 +55,7 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
* permtable index flag
|
||||
*/
|
||||
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
bool permindex): eq(eq)
|
||||
bool permindex, bool prompt): eq(eq)
|
||||
{
|
||||
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
|
||||
fprintf(stderr, "Compressing HFA:\r");
|
||||
@@ -118,10 +114,12 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
||||
dfa.nonmatching->map_perms_to_accept(accept[0],
|
||||
accept2[0],
|
||||
accept3);
|
||||
accept3,
|
||||
prompt);
|
||||
dfa.start->map_perms_to_accept(accept[1],
|
||||
accept2[1],
|
||||
accept3);
|
||||
accept3,
|
||||
prompt);
|
||||
}
|
||||
next_check.resize(max(optimal, (size_t) dfa.max_range));
|
||||
free_list.resize(next_check.size());
|
||||
@@ -145,7 +143,8 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
else
|
||||
(*i)->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()],
|
||||
accept3);
|
||||
accept3,
|
||||
prompt);
|
||||
num.insert(make_pair(*i, num.size()));
|
||||
}
|
||||
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
||||
@@ -167,7 +166,8 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
else
|
||||
i->second->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()],
|
||||
accept3);
|
||||
accept3,
|
||||
prompt);
|
||||
num.insert(make_pair(i->second, num.size()));
|
||||
}
|
||||
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
||||
@@ -515,3 +515,115 @@ void CHFA::flex_table(ostream &os, optflags const &opts) {
|
||||
flex_table_serialize<uint16_t>(*this, os, (1 << 16) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @file_chfa: chfa to add on to the policy chfa
|
||||
* @new_start: new start state for where the @file_dfa is in the new chfa
|
||||
*
|
||||
* Make a new chfa that is a combination of policy and file chfas. It
|
||||
* assumes policy is built with AA_CLASS_FILE support transition. The
|
||||
* resultant chfa will have file states and indexes offset except for
|
||||
* start and null states.
|
||||
*
|
||||
* NOTE:
|
||||
* - modifies chfa
|
||||
* requires:
|
||||
* - no ec
|
||||
* - policy chfa has transitions state[start].next[AA_CLASS_FILE]
|
||||
* - policy perms table is build if using permstable
|
||||
|
||||
*/
|
||||
void CHFA::weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
|
||||
bool accept_idx, bool prompt,
|
||||
vector <aa_perms> &policy_perms,
|
||||
vector <aa_perms> &file_perms)
|
||||
{
|
||||
// doesn't support remapping eq classes yet
|
||||
if (eq.size() > 0 || file_chfa.eq.size() > 0)
|
||||
throw 1;
|
||||
|
||||
size_t old_base_size = default_base.size();
|
||||
size_t old_next_size = next_check.size();
|
||||
|
||||
const State *nonmatching = default_base[0].first;
|
||||
//const State *start = default_base[1].first;
|
||||
const State *file_nonmatching = file_chfa.default_base[0].first;
|
||||
|
||||
// renumber states from file_dfa by appending to policy dfa
|
||||
num.insert(make_pair(file_nonmatching, 0)); // remap to policy nonmatching
|
||||
for (map<const State *, size_t>::iterator i = file_chfa.num.begin(); i != file_chfa.num.end() ; i++) {
|
||||
if (i->first == file_nonmatching)
|
||||
continue;
|
||||
num.insert(make_pair(i->first, i->second + old_base_size));
|
||||
}
|
||||
|
||||
// handle default and base table expansion, and setup renumbering
|
||||
// while we remap file_nonmatch within the table, we still keep its
|
||||
// slot.
|
||||
bool first = true;
|
||||
for (DefaultBase::iterator i = file_chfa.default_base.begin(); i != file_chfa.default_base.end(); i++) {
|
||||
const State *def;
|
||||
size_t base;
|
||||
if (first) {
|
||||
first = false;
|
||||
// remap file_nonmatch to nonmatch
|
||||
def = nonmatching;
|
||||
base = 0;
|
||||
} else {
|
||||
def = i->first;
|
||||
base = i->second + old_next_size;
|
||||
}
|
||||
default_base.push_back(make_pair(def, base));
|
||||
}
|
||||
|
||||
// mapping for these are handled by num[]
|
||||
for (NextCheck::iterator i = file_chfa.next_check.begin(); i != file_chfa.next_check.end(); i++) {
|
||||
next_check.push_back(*i);
|
||||
}
|
||||
|
||||
// append file perms to policy perms, and rework permsidx if needed
|
||||
if (accept_idx) {
|
||||
// policy idx double
|
||||
// file + doubled offset
|
||||
// Requires: policy perms table, so we can double and
|
||||
// update indexes
|
||||
// * file perm idx to start on even idx
|
||||
// * policy perms table size to double and entries
|
||||
// to repeat
|
||||
assert(accept.size() == old_base_size);
|
||||
accept.resize(accept.size() + file_chfa.accept.size());
|
||||
size_t size = policy_perms.size();
|
||||
policy_perms.resize(size*2 + file_perms.size());
|
||||
// shift and double the policy perms
|
||||
for (size_t i = size - 1; size >= 0; i--) {
|
||||
policy_perms[i*2] = policy_perms[i];
|
||||
policy_perms[i*2 + 1] = policy_perms[i];
|
||||
}
|
||||
// update policy accept idx for the new shifted perms table
|
||||
for (size_t i = 0; i < old_base_size; i++) {
|
||||
accept[i] = accept[i]*2;
|
||||
}
|
||||
// copy over file perms
|
||||
for (size_t i = 0; i < file_perms.size(); i++) {
|
||||
policy_perms[size*2 + i] = file_perms[i];
|
||||
}
|
||||
// shift file accept indexs
|
||||
for (size_t i = 0; i < file_chfa.accept.size(); i++) {
|
||||
accept[old_base_size + i] = file_chfa.accept[i] + size*2;
|
||||
}
|
||||
} else {
|
||||
// perms are stored in accept just append the perms
|
||||
size_t size = accept.size();
|
||||
accept.resize(size + file_chfa.accept.size());
|
||||
accept2.resize(size + file_chfa.accept.size());
|
||||
for (size_t i = 0; i < file_chfa.accept.size(); i++) {
|
||||
accept[size + i] = file_chfa.accept[i];
|
||||
accept2[size + i] = file_chfa.accept2[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Rework transition state[start].next[AA_CLASS_FILE]
|
||||
next_check[default_base[1].second + AA_CLASS_FILE].first = file_chfa.start;
|
||||
|
||||
new_start = num[file_chfa.start];
|
||||
}
|
||||
|
@@ -32,33 +32,39 @@
|
||||
#define MATCH_FLAG_OOB_TRANSITION 0x20000000
|
||||
#define base_mask_size(X) ((X) & ~BASE32_FLAGS)
|
||||
|
||||
typedef std::vector<std::pair<const State *, size_t> > DefaultBase;
|
||||
typedef std::vector<std::pair<const State *, const State *> > NextCheck;
|
||||
using namespace std;
|
||||
|
||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||
|
||||
class CHFA {
|
||||
public:
|
||||
CHFA(void);
|
||||
CHFA(DFA &dfa, std::map<transchar, transchar> &eq, optflags const &opts,
|
||||
bool permindex);
|
||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
bool permindex, bool prompt);
|
||||
void dump(ostream & os);
|
||||
void flex_table(ostream &os, optflags const &opts);
|
||||
void init_free_list(std::vector<std::pair<size_t, size_t> > &free_list,
|
||||
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
size_t prev, size_t start);
|
||||
bool fits_in(std::vector<std::pair<size_t, size_t> > &free_list, size_t base,
|
||||
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
||||
StateTrans &cases);
|
||||
void insert_state(std::vector<std::pair<size_t, size_t> > &free_list,
|
||||
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
State *state, DFA &dfa);
|
||||
void weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
|
||||
bool accept_idx, bool prompt,
|
||||
vector <aa_perms> &policy_perms,
|
||||
vector <aa_perms> &file_perms);
|
||||
|
||||
// private:
|
||||
// sigh templates suck, friend declaration does not work so for now
|
||||
// make these public
|
||||
std::vector<uint32_t> accept;
|
||||
std::vector<uint32_t> accept2;
|
||||
vector<uint32_t> accept;
|
||||
vector<uint32_t> accept2;
|
||||
DefaultBase default_base;
|
||||
NextCheck next_check;
|
||||
const State *start;
|
||||
Renumber_Map num;
|
||||
std::map<transchar, transchar> eq;
|
||||
map<const State *, size_t> num;
|
||||
map<transchar, transchar> eq;
|
||||
unsigned int chfaflags;
|
||||
private:
|
||||
transchar max_eq;
|
||||
|
@@ -38,8 +38,6 @@
|
||||
#include "expr-tree.h"
|
||||
#include "apparmor_re.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* Use a single static EpsNode as it carries no node specific information */
|
||||
EpsNode epsnode;
|
||||
|
||||
|
@@ -44,6 +44,8 @@
|
||||
#include "../perms.h"
|
||||
#include "apparmor_re.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* transchar - representative input character for state transitions
|
||||
*
|
||||
@@ -144,9 +146,9 @@ public:
|
||||
|
||||
class Chars {
|
||||
public:
|
||||
std::set<transchar> chars;
|
||||
set<transchar> chars;
|
||||
|
||||
typedef std::set<transchar>::iterator iterator;
|
||||
typedef set<transchar>::iterator iterator;
|
||||
iterator begin() { return chars.begin(); }
|
||||
iterator end() { return chars.end(); }
|
||||
|
||||
@@ -164,11 +166,11 @@ public:
|
||||
{
|
||||
return chars.find(key);
|
||||
}
|
||||
std::pair<iterator,bool> insert(transchar c)
|
||||
pair<iterator,bool> insert(transchar c)
|
||||
{
|
||||
return chars.insert(c);
|
||||
}
|
||||
std::pair<iterator,bool> insert(char c)
|
||||
pair<iterator,bool> insert(char c)
|
||||
{
|
||||
transchar tmp(c);
|
||||
return chars.insert(tmp);
|
||||
@@ -179,9 +181,9 @@ public:
|
||||
ostream &operator<<(ostream &os, transchar c);
|
||||
|
||||
/* Compute the union of two sets. */
|
||||
template<class T> std::set<T> operator+(const std::set<T> &a, const std::set<T> &b)
|
||||
template<class T> set<T> operator+(const set<T> &a, const set<T> &b)
|
||||
{
|
||||
std::set<T> c(a);
|
||||
set<T> c(a);
|
||||
c.insert(b.begin(), b.end());
|
||||
return c;
|
||||
}
|
||||
@@ -194,7 +196,7 @@ template<class T> std::set<T> operator+(const std::set<T> &a, const std::set<T>
|
||||
*/
|
||||
class Node;
|
||||
class ImportantNode;
|
||||
typedef std::set<ImportantNode *> NodeSet;
|
||||
typedef set<ImportantNode *> NodeSet;
|
||||
|
||||
/**
|
||||
* Text-dump a state (for debugging).
|
||||
@@ -210,12 +212,12 @@ ostream &operator<<(ostream &os, const NodeSet &state);
|
||||
* enumerating all the explicit tranitions for default matches.
|
||||
*/
|
||||
typedef struct Cases {
|
||||
typedef std::map<transchar, NodeSet *>::iterator iterator;
|
||||
typedef map<transchar, NodeSet *>::iterator iterator;
|
||||
iterator begin() { return cases.begin(); }
|
||||
iterator end() { return cases.end(); }
|
||||
|
||||
Cases(): otherwise(0) { }
|
||||
std::map<transchar, NodeSet *> cases;
|
||||
map<transchar, NodeSet *> cases;
|
||||
NodeSet *otherwise;
|
||||
} Cases;
|
||||
|
||||
@@ -243,7 +245,6 @@ ostream &operator<<(ostream &os, Node &node);
|
||||
#define NODE_TYPE_MATCHFLAG (1 << 18)
|
||||
#define NODE_TYPE_EXACTMATCHFLAG (1 << 19)
|
||||
#define NODE_TYPE_DENYMATCHFLAG (1 << 20)
|
||||
#define NODE_TYPE_PROMPTMATCHFLAG (1 << 21)
|
||||
|
||||
/* An abstract node in the syntax tree. */
|
||||
class Node {
|
||||
@@ -371,13 +372,13 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_TWOCHILD;
|
||||
};
|
||||
int normalize_eps(int dir) override;
|
||||
virtual int normalize_eps(int dir);
|
||||
};
|
||||
|
||||
class LeafNode: public Node {
|
||||
public:
|
||||
LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; };
|
||||
void normalize(int dir __attribute__((unused))) override { return; }
|
||||
virtual void normalize(int dir __attribute__((unused))) { return; }
|
||||
};
|
||||
|
||||
/* Match nothing (//). */
|
||||
@@ -389,22 +390,22 @@ public:
|
||||
nullable = true;
|
||||
label = 0;
|
||||
}
|
||||
void release(void) override
|
||||
void release(void)
|
||||
{
|
||||
/* don't delete Eps nodes because there is a single static
|
||||
* instance shared by all trees. Look for epsnode in the code
|
||||
*/
|
||||
}
|
||||
|
||||
void compute_firstpos() override { }
|
||||
void compute_lastpos() override { }
|
||||
int eq(Node *other) override
|
||||
void compute_firstpos() { }
|
||||
void compute_lastpos() { }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_EPS))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
return os << "[]";
|
||||
}
|
||||
@@ -418,8 +419,8 @@ public:
|
||||
class ImportantNode: public LeafNode {
|
||||
public:
|
||||
ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; }
|
||||
void compute_firstpos() override { firstpos.insert(this); }
|
||||
void compute_lastpos() override { lastpos.insert(this); }
|
||||
void compute_firstpos() { firstpos.insert(this); }
|
||||
void compute_lastpos() { lastpos.insert(this); }
|
||||
virtual void follow(Cases &cases) = 0;
|
||||
virtual int is_accept(void) = 0;
|
||||
virtual int is_postprocess(void) = 0;
|
||||
@@ -431,15 +432,15 @@ public:
|
||||
class CNode: public ImportantNode {
|
||||
public:
|
||||
CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; }
|
||||
int is_accept(void) override { return false; }
|
||||
int is_postprocess(void) override { return false; }
|
||||
int is_accept(void) { return false; }
|
||||
int is_postprocess(void) { return false; }
|
||||
};
|
||||
|
||||
/* Match one specific character (/c/). */
|
||||
class CharNode: public CNode {
|
||||
public:
|
||||
CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; }
|
||||
void follow(Cases &cases) override
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
NodeSet **x = &cases.cases[c];
|
||||
if (!*x) {
|
||||
@@ -450,7 +451,7 @@ public:
|
||||
}
|
||||
(*x)->insert(followpos.begin(), followpos.end());
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_CHAR)) {
|
||||
CharNode *o = static_cast<CharNode *>(other);
|
||||
@@ -458,12 +459,12 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
return os << c;
|
||||
}
|
||||
|
||||
int min_match_len() override
|
||||
int min_match_len()
|
||||
{
|
||||
if (c < 0) {
|
||||
// oob characters indicates end of string.
|
||||
@@ -475,7 +476,7 @@ public:
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool contains_oob() override { return c < 0; }
|
||||
bool contains_oob() { return c < 0; }
|
||||
|
||||
transchar c;
|
||||
};
|
||||
@@ -487,7 +488,7 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_CHARSET;
|
||||
}
|
||||
void follow(Cases &cases) override
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
NodeSet **x = &cases.cases[*i];
|
||||
@@ -500,7 +501,7 @@ public:
|
||||
(*x)->insert(followpos.begin(), followpos.end());
|
||||
}
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (!other->is_type(NODE_TYPE_CHARSET))
|
||||
return 0;
|
||||
@@ -516,7 +517,7 @@ public:
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << '[';
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++)
|
||||
@@ -524,7 +525,7 @@ public:
|
||||
return os << ']';
|
||||
}
|
||||
|
||||
int min_match_len() override
|
||||
int min_match_len()
|
||||
{
|
||||
if (contains_oob()) {
|
||||
return 0;
|
||||
@@ -532,7 +533,7 @@ public:
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool contains_oob() override
|
||||
bool contains_oob()
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
if (*i < 0) {
|
||||
@@ -552,7 +553,7 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_NOTCHARSET;
|
||||
}
|
||||
void follow(Cases &cases) override
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
cases.otherwise = new NodeSet;
|
||||
@@ -573,7 +574,7 @@ public:
|
||||
followpos.end());
|
||||
}
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (!other->is_type(NODE_TYPE_NOTCHARSET))
|
||||
return 0;
|
||||
@@ -589,7 +590,7 @@ public:
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << "[^";
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++)
|
||||
@@ -597,7 +598,7 @@ public:
|
||||
return os << ']';
|
||||
}
|
||||
|
||||
int min_match_len() override
|
||||
int min_match_len()
|
||||
{
|
||||
/* Inverse match does not match any oob char at this time
|
||||
* so only count characters
|
||||
@@ -605,7 +606,7 @@ public:
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool contains_oob() override
|
||||
bool contains_oob()
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
if (*i < 0) {
|
||||
@@ -622,7 +623,7 @@ public:
|
||||
class AnyCharNode: public CNode {
|
||||
public:
|
||||
AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; }
|
||||
void follow(Cases &cases) override
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
cases.otherwise = new NodeSet;
|
||||
@@ -633,13 +634,13 @@ public:
|
||||
if (i->first.c >= 0)
|
||||
i->second->insert(followpos.begin(), followpos.end());
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_ANYCHAR))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override { return os << "."; }
|
||||
ostream &dump(ostream &os) { return os << "."; }
|
||||
};
|
||||
|
||||
/* Match a node zero or more times. (This is a unary operator.) */
|
||||
@@ -650,29 +651,29 @@ public:
|
||||
type_flags |= NODE_TYPE_STAR;
|
||||
nullable = true;
|
||||
}
|
||||
void compute_firstpos() override { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() override { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos() override
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos()
|
||||
{
|
||||
NodeSet from = child[0]->lastpos, to = child[0]->firstpos;
|
||||
for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
|
||||
(*i)->followpos.insert(to.begin(), to.end());
|
||||
}
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_STAR))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << '(';
|
||||
child[0]->dump(os);
|
||||
return os << ")*";
|
||||
}
|
||||
|
||||
bool contains_oob() override { return child[0]->contains_oob(); }
|
||||
bool contains_oob() { return child[0]->contains_oob(); }
|
||||
};
|
||||
|
||||
/* Match a node zero or one times. */
|
||||
@@ -683,15 +684,15 @@ public:
|
||||
type_flags |= NODE_TYPE_OPTIONAL;
|
||||
nullable = true;
|
||||
}
|
||||
void compute_firstpos() override { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() override { lastpos = child[0]->lastpos; }
|
||||
int eq(Node *other) override
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_OPTIONAL))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << '(';
|
||||
child[0]->dump(os);
|
||||
@@ -706,28 +707,28 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_PLUS;
|
||||
}
|
||||
void compute_nullable() override { nullable = child[0]->nullable; }
|
||||
void compute_firstpos() override { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() override { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos() override
|
||||
void compute_nullable() { nullable = child[0]->nullable; }
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos()
|
||||
{
|
||||
NodeSet from = child[0]->lastpos, to = child[0]->firstpos;
|
||||
for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
|
||||
(*i)->followpos.insert(to.begin(), to.end());
|
||||
}
|
||||
}
|
||||
int eq(Node *other) override {
|
||||
int eq(Node *other) {
|
||||
if (other->is_type(NODE_TYPE_PLUS))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override {
|
||||
ostream &dump(ostream &os) {
|
||||
os << '(';
|
||||
child[0]->dump(os);
|
||||
return os << ")+";
|
||||
}
|
||||
int min_match_len() override { return child[0]->min_match_len(); }
|
||||
bool contains_oob() override { return child[0]->contains_oob(); }
|
||||
int min_match_len() { return child[0]->min_match_len(); }
|
||||
bool contains_oob() { return child[0]->contains_oob(); }
|
||||
};
|
||||
|
||||
/* Match a pair of consecutive nodes. */
|
||||
@@ -737,32 +738,32 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_CAT;
|
||||
}
|
||||
void compute_nullable() override
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable && child[1]->nullable;
|
||||
}
|
||||
void compute_firstpos() override
|
||||
void compute_firstpos()
|
||||
{
|
||||
if (child[0]->nullable)
|
||||
firstpos = child[0]->firstpos + child[1]->firstpos;
|
||||
else
|
||||
firstpos = child[0]->firstpos;
|
||||
}
|
||||
void compute_lastpos() override
|
||||
void compute_lastpos()
|
||||
{
|
||||
if (child[1]->nullable)
|
||||
lastpos = child[0]->lastpos + child[1]->lastpos;
|
||||
else
|
||||
lastpos = child[1]->lastpos;
|
||||
}
|
||||
void compute_followpos() override
|
||||
void compute_followpos()
|
||||
{
|
||||
NodeSet from = child[0]->lastpos, to = child[1]->firstpos;
|
||||
for (NodeSet::iterator i = from.begin(); i != from.end(); i++) {
|
||||
(*i)->followpos.insert(to.begin(), to.end());
|
||||
}
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_CAT)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
@@ -771,14 +772,14 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
child[0]->dump(os);
|
||||
child[1]->dump(os);
|
||||
return os;
|
||||
}
|
||||
void normalize(int dir) override;
|
||||
int min_match_len() override
|
||||
void normalize(int dir);
|
||||
int min_match_len()
|
||||
{
|
||||
int len = child[0]->min_match_len();
|
||||
if (child[0]->contains_oob()) {
|
||||
@@ -790,7 +791,7 @@ public:
|
||||
}
|
||||
return len + child[1]->min_match_len();
|
||||
}
|
||||
bool contains_oob() override
|
||||
bool contains_oob()
|
||||
{
|
||||
return child[0]->contains_oob() || child[1]->contains_oob();
|
||||
}
|
||||
@@ -803,19 +804,19 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_ALT;
|
||||
}
|
||||
void compute_nullable() override
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable || child[1]->nullable;
|
||||
}
|
||||
void compute_lastpos() override
|
||||
void compute_lastpos()
|
||||
{
|
||||
lastpos = child[0]->lastpos + child[1]->lastpos;
|
||||
}
|
||||
void compute_firstpos() override
|
||||
void compute_firstpos()
|
||||
{
|
||||
firstpos = child[0]->firstpos + child[1]->firstpos;
|
||||
}
|
||||
int eq(Node *other) override
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_ALT)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
@@ -824,7 +825,7 @@ public:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ostream &dump(ostream &os) override
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << '(';
|
||||
child[0]->dump(os);
|
||||
@@ -833,8 +834,8 @@ public:
|
||||
os << ')';
|
||||
return os;
|
||||
}
|
||||
void normalize(int dir) override;
|
||||
int min_match_len() override
|
||||
void normalize(int dir);
|
||||
int min_match_len()
|
||||
{
|
||||
int m1, m2;
|
||||
m1 = child[0]->min_match_len();
|
||||
@@ -844,7 +845,7 @@ public:
|
||||
}
|
||||
return m2;
|
||||
}
|
||||
bool contains_oob() override
|
||||
bool contains_oob()
|
||||
{
|
||||
return child[0]->contains_oob() || child[1]->contains_oob();
|
||||
}
|
||||
@@ -856,20 +857,20 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_SHARED;
|
||||
}
|
||||
void release(void) override
|
||||
void release(void)
|
||||
{
|
||||
/* don't delete SharedNodes via release as they are shared, and
|
||||
* will be deleted when the table they are stored in is deleted
|
||||
*/
|
||||
}
|
||||
|
||||
void follow(Cases &cases __attribute__ ((unused))) override
|
||||
void follow(Cases &cases __attribute__ ((unused)))
|
||||
{
|
||||
/* Nothing to follow. */
|
||||
}
|
||||
|
||||
/* requires shared nodes to be common by pointer */
|
||||
int eq(Node *other) override { return (this == other); }
|
||||
int eq(Node *other) { return (this == other); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -879,8 +880,8 @@ public:
|
||||
class AcceptNode: public SharedNode {
|
||||
public:
|
||||
AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; }
|
||||
int is_accept(void) override { return true; }
|
||||
int is_postprocess(void) override { return false; }
|
||||
int is_accept(void) { return true; }
|
||||
int is_postprocess(void) { return false; }
|
||||
};
|
||||
|
||||
class MatchFlag: public AcceptNode {
|
||||
@@ -889,8 +890,7 @@ public:
|
||||
{
|
||||
type_flags |= NODE_TYPE_MATCHFLAG;
|
||||
}
|
||||
|
||||
ostream &dump(ostream &os) override { return os << "< 0x" << std::hex << perms << std::dec << '>'; }
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << std::dec << '>'; }
|
||||
|
||||
int priority;
|
||||
perm32_t perms;
|
||||
@@ -915,16 +915,13 @@ public:
|
||||
|
||||
class PromptMatchFlag: public MatchFlag {
|
||||
public:
|
||||
PromptMatchFlag(int priority, perm32_t prompt, perm32_t audit): MatchFlag(priority, prompt, audit)
|
||||
{
|
||||
type_flags |= NODE_TYPE_PROMPTMATCHFLAG;
|
||||
}
|
||||
PromptMatchFlag(int priority, perm32_t prompt, perm32_t audit): MatchFlag(priority, prompt, audit) {}
|
||||
};
|
||||
|
||||
|
||||
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
||||
class depth_first_traversal {
|
||||
std::stack<Node *>pos;
|
||||
stack<Node *>pos;
|
||||
void push_left(Node *node) {
|
||||
pos.push(node);
|
||||
|
||||
@@ -1032,7 +1029,6 @@ public:
|
||||
|
||||
class CacheStats {
|
||||
public:
|
||||
virtual ~CacheStats() {}
|
||||
unsigned long dup, sum, max;
|
||||
|
||||
CacheStats(void): dup(0), sum(0), max(0) { };
|
||||
@@ -1050,16 +1046,16 @@ struct deref_less_than {
|
||||
|
||||
class NodeVecCache: public CacheStats {
|
||||
public:
|
||||
std::set<NodeVec *, deref_less_than> cache;
|
||||
set<NodeVec *, deref_less_than> cache;
|
||||
|
||||
NodeVecCache(void): cache() { };
|
||||
~NodeVecCache() override { clear(); };
|
||||
~NodeVecCache() { clear(); };
|
||||
|
||||
unsigned long size(void) const override { return cache.size(); }
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (std::set<NodeVec *>::iterator i = cache.begin();
|
||||
for (set<NodeVec *>::iterator i = cache.begin();
|
||||
i != cache.end(); i++) {
|
||||
delete *i;
|
||||
}
|
||||
@@ -1071,7 +1067,7 @@ public:
|
||||
{
|
||||
if (!nodes)
|
||||
return NULL;
|
||||
std::pair<std::set<NodeVec *>::iterator,bool> uniq;
|
||||
pair<set<NodeVec *>::iterator,bool> uniq;
|
||||
NodeVec *nv = new NodeVec(nodes);
|
||||
uniq = cache.insert(nv);
|
||||
if (uniq.second == false) {
|
||||
|
@@ -38,8 +38,6 @@
|
||||
#include "../immunix.h"
|
||||
#include "../perms.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ostream &operator<<(ostream &os, const CacheStats &cache)
|
||||
{
|
||||
/* dump the state label */
|
||||
@@ -85,27 +83,6 @@ ostream &operator<<(ostream &os, State &state)
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, perms_t &perms)
|
||||
{
|
||||
perms.dump(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os,
|
||||
const std::pair<State * const, Renumber_Map *> &p)
|
||||
{
|
||||
/* dump the state label */
|
||||
if (p.second && (*p.second)[p.first] != (size_t) p.first->label) {
|
||||
os << '{';
|
||||
os << (*p.second)[p.first];
|
||||
os << " == " << *(p.first);
|
||||
os << '}';
|
||||
} else {
|
||||
os << *(p.first);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* diff_weight - Find differential compression distance between @rel and @this
|
||||
* @rel: State to compare too
|
||||
@@ -325,8 +302,7 @@ static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
|
||||
*nnodes = nodes;
|
||||
}
|
||||
|
||||
State *DFA::add_new_state(optflags const &opts, NodeSet *anodes,
|
||||
NodeSet *nnodes, State *other)
|
||||
State *DFA::add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other)
|
||||
{
|
||||
NodeVec *nnodev, *anodev;
|
||||
nnodev = nnodes_cache.insert(nnodes);
|
||||
@@ -334,16 +310,7 @@ State *DFA::add_new_state(optflags const &opts, NodeSet *anodes,
|
||||
|
||||
ProtoState proto;
|
||||
proto.init(nnodev, anodev);
|
||||
State *state;
|
||||
try {
|
||||
state = new State(opts, node_map.size(), proto, other, filedfa);
|
||||
} catch(int error) {
|
||||
/* this function is called in the DFA object creation,
|
||||
* and the exception prevents the destructor from
|
||||
* being called, so call the helper here */
|
||||
cleanup();
|
||||
throw error;
|
||||
}
|
||||
State *state = new State(node_map.size(), proto, other, filedfa);
|
||||
pair<NodeMap::iterator,bool> x = node_map.insert(proto, state);
|
||||
if (x.second == false) {
|
||||
delete state;
|
||||
@@ -355,7 +322,7 @@ State *DFA::add_new_state(optflags const &opts, NodeSet *anodes,
|
||||
return x.first->second;
|
||||
}
|
||||
|
||||
State *DFA::add_new_state(optflags const &opts, NodeSet *nodes, State *other)
|
||||
State *DFA::add_new_state(NodeSet *nodes, State *other)
|
||||
{
|
||||
/* The splitting of nodes should probably get pushed down into
|
||||
* follow(), ie. put in separate lists from the start
|
||||
@@ -363,12 +330,12 @@ State *DFA::add_new_state(optflags const &opts, NodeSet *nodes, State *other)
|
||||
NodeSet *anodes, *nnodes;
|
||||
split_node_types(nodes, &anodes, &nnodes);
|
||||
|
||||
State *state = add_new_state(opts, anodes, nnodes, other);
|
||||
State *state = add_new_state(anodes, nnodes, other);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void DFA::update_state_transitions(optflags const &opts, State *state)
|
||||
void DFA::update_state_transitions(State *state)
|
||||
{
|
||||
/* Compute possible transitions for state->nodes. This is done by
|
||||
* iterating over all the nodes in state->nodes and combining the
|
||||
@@ -391,8 +358,7 @@ void DFA::update_state_transitions(optflags const &opts, State *state)
|
||||
|
||||
/* check the default transition first */
|
||||
if (cases.otherwise)
|
||||
state->otherwise = add_new_state(opts, cases.otherwise,
|
||||
nonmatching);
|
||||
state->otherwise = add_new_state(cases.otherwise, nonmatching);
|
||||
else
|
||||
state->otherwise = nonmatching;
|
||||
|
||||
@@ -401,17 +367,7 @@ void DFA::update_state_transitions(optflags const &opts, State *state)
|
||||
*/
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
State *target;
|
||||
try {
|
||||
target = add_new_state(opts, j->second, nonmatching);
|
||||
} catch (int error) {
|
||||
/* when add_new_state fails, there could still
|
||||
* be NodeSets in the rest of cases, so clean
|
||||
* them up before re-throwing the exception */
|
||||
for (Cases::iterator k = ++j; k != cases.end(); k++) {
|
||||
delete k->second;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
target = add_new_state(j->second, nonmatching);
|
||||
|
||||
/* Don't insert transition that the otherwise transition
|
||||
* already covers
|
||||
@@ -458,7 +414,7 @@ void DFA::process_work_queue(const char *header, optflags const &opts)
|
||||
/* Update 'from's transitions, and if it transitions to any
|
||||
* unknown State create it and add it to the work_queue
|
||||
*/
|
||||
update_state_transitions(opts, from);
|
||||
update_state_transitions(from);
|
||||
} /* while (!work_queue.empty()) */
|
||||
}
|
||||
|
||||
@@ -488,8 +444,8 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
(*i)->compute_followpos();
|
||||
}
|
||||
|
||||
nonmatching = add_new_state(opts, new NodeSet, NULL);
|
||||
start = add_new_state(opts, new NodeSet(root->firstpos), nonmatching);
|
||||
nonmatching = add_new_state(new NodeSet, NULL);
|
||||
start = add_new_state(new NodeSet(root->firstpos), nonmatching);
|
||||
|
||||
/* the work_queue contains the states that need to have their
|
||||
* transitions computed. This could be done with a recursive
|
||||
@@ -537,11 +493,20 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
*/
|
||||
nnodes_cache.clear();
|
||||
node_map.clear();
|
||||
/* once created the priority information is no longer needed and
|
||||
* can prevent sets with the same perms and different priorities
|
||||
* from being merged during minimization
|
||||
*/
|
||||
clear_priorities();
|
||||
}
|
||||
|
||||
DFA::~DFA()
|
||||
{
|
||||
cleanup();
|
||||
anodes_cache.clear();
|
||||
nnodes_cache.clear();
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
delete *i;
|
||||
}
|
||||
|
||||
State *DFA::match_len(State *state, const char *str, size_t len)
|
||||
@@ -581,14 +546,6 @@ void DFA::dump_uniq_perms(const char *s)
|
||||
//TODO: add prompt
|
||||
}
|
||||
|
||||
// make sure work_queue and reachable insertion are always done together
|
||||
static void push_reachable(set<State *> &reachable, list<State *> &work_queue,
|
||||
State *state)
|
||||
{
|
||||
work_queue.push_back(state);
|
||||
reachable.insert(state);
|
||||
}
|
||||
|
||||
/* Remove dead or unreachable states */
|
||||
void DFA::remove_unreachable(optflags const &opts)
|
||||
{
|
||||
@@ -596,18 +553,19 @@ void DFA::remove_unreachable(optflags const &opts)
|
||||
|
||||
/* find the set of reachable states */
|
||||
reachable.insert(nonmatching);
|
||||
push_reachable(reachable, work_queue, start);
|
||||
work_queue.push_back(start);
|
||||
while (!work_queue.empty()) {
|
||||
State *from = work_queue.front();
|
||||
work_queue.pop_front();
|
||||
reachable.insert(from);
|
||||
|
||||
if (from->otherwise != nonmatching &&
|
||||
reachable.find(from->otherwise) == reachable.end())
|
||||
push_reachable(reachable, work_queue, from->otherwise);
|
||||
work_queue.push_back(from->otherwise);
|
||||
|
||||
for (StateTrans::iterator j = from->trans.begin(); j != from->trans.end(); j++) {
|
||||
if (reachable.find(j->second) == reachable.end())
|
||||
push_reachable(reachable, work_queue, j->second);
|
||||
work_queue.push_back(j->second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,39 +651,13 @@ int DFA::apply_and_clear_deny(void)
|
||||
return c;
|
||||
}
|
||||
|
||||
ostream &DFA::dump_partition(ostream &os, Partition &p)
|
||||
void DFA::clear_priorities(void)
|
||||
{
|
||||
/* first entry is the representative state */
|
||||
for (Partition::iterator i = p.begin(); i != p.end(); i++) {
|
||||
os << **i;
|
||||
if (i == p.begin())
|
||||
os << " : ";
|
||||
else
|
||||
os << ", ";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
return os;
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
(*i)->perms.priority = 0;
|
||||
}
|
||||
|
||||
|
||||
ostream &DFA::dump_partitions(ostream &os, const char *description,
|
||||
list<Partition *> &partitions)
|
||||
{
|
||||
size_t j = 0;
|
||||
|
||||
os << "Dumping Minimization partition mapping: " << description << "\n";
|
||||
for (list<Partition *>::iterator p = partitions.begin();
|
||||
p != partitions.end(); p++) {
|
||||
os << " [" << j++ << "] ";
|
||||
os << (*(*p)->begin())->perms << ": ";
|
||||
(void) dump_partition(os, **p);
|
||||
os << "\n";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/* minimize the number of dfa states */
|
||||
void DFA::minimize(optflags const &opts)
|
||||
@@ -759,9 +691,6 @@ void DFA::minimize(optflags const &opts)
|
||||
<< " (accept " << accept_count << ")\r";
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
(void) dump_partitions(cerr, "Initial", partitions);
|
||||
|
||||
/* perm_map is no longer needed so free the memory it is using.
|
||||
* Don't remove - doing it manually here helps reduce peak memory usage.
|
||||
*/
|
||||
@@ -827,9 +756,6 @@ void DFA::minimize(optflags const &opts)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
(void) dump_partitions(cerr, "Pre-remap", partitions);
|
||||
|
||||
/* Remap the dfa so it uses the representative states
|
||||
* Use the first state of a partition as the representative state
|
||||
* At this point all states with in a partition have transitions
|
||||
@@ -1149,11 +1075,11 @@ void DFA::dump_diff_encode(ostream &os)
|
||||
/**
|
||||
* text-dump the DFA (for debugging).
|
||||
*/
|
||||
void DFA::dump(ostream &os, Renumber_Map *renum)
|
||||
void DFA::dump(ostream & os)
|
||||
{
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if (*i == start || (*i)->perms.is_accept()) {
|
||||
os << make_pair(*i, renum);
|
||||
os << **i;
|
||||
if (*i == start) {
|
||||
os << " <== ";
|
||||
(*i)->perms.dump_header(os);
|
||||
@@ -1176,7 +1102,7 @@ void DFA::dump(ostream &os, Renumber_Map *renum)
|
||||
} else {
|
||||
if (first) {
|
||||
first = false;
|
||||
os << make_pair(*i, renum) << " perms: ";
|
||||
os << **i << " perms: ";
|
||||
if ((*i)->perms.is_accept())
|
||||
(*i)->perms.dump(os);
|
||||
else
|
||||
@@ -1184,7 +1110,7 @@ void DFA::dump(ostream &os, Renumber_Map *renum)
|
||||
os << "\n";
|
||||
}
|
||||
os << " "; j->first.dump(os) << " -> " <<
|
||||
make_pair(j->second, renum);
|
||||
*(j)->second;
|
||||
if ((j)->second->perms.is_accept())
|
||||
os << " ", (j->second)->perms.dump(os);
|
||||
os << "\n";
|
||||
@@ -1194,7 +1120,7 @@ void DFA::dump(ostream &os, Renumber_Map *renum)
|
||||
if ((*i)->otherwise != nonmatching) {
|
||||
if (first) {
|
||||
first = false;
|
||||
os << make_pair(*i, renum) << " perms: ";
|
||||
os << **i << " perms: ";
|
||||
if ((*i)->perms.is_accept())
|
||||
(*i)->perms.dump(os);
|
||||
else
|
||||
@@ -1209,7 +1135,7 @@ void DFA::dump(ostream &os, Renumber_Map *renum)
|
||||
os << *k;
|
||||
}
|
||||
}
|
||||
os << "] -> " << make_pair((*i)->otherwise, renum);
|
||||
os << "] -> " << *(*i)->otherwise;
|
||||
if ((*i)->otherwise->perms.is_accept())
|
||||
os << " ", (*i)->otherwise->perms.dump(os);
|
||||
os << "\n";
|
||||
@@ -1382,12 +1308,13 @@ void DFA::apply_equivalence_classes(map<transchar, transchar> &eq)
|
||||
}
|
||||
|
||||
void DFA::compute_perms_table_ent(State *state, size_t pos,
|
||||
vector <aa_perms> &perms_table)
|
||||
vector <aa_perms> &perms_table,
|
||||
bool prompt)
|
||||
{
|
||||
uint32_t accept1, accept2, accept3;
|
||||
|
||||
// until front end doesn't map the way it does
|
||||
state->map_perms_to_accept(accept1, accept2, accept3);
|
||||
state->map_perms_to_accept(accept1, accept2, accept3, prompt);
|
||||
if (filedfa) {
|
||||
state->idx = pos * 2;
|
||||
perms_table[pos*2] = compute_fperms_user(accept1, accept2, accept3);
|
||||
@@ -1398,7 +1325,7 @@ void DFA::compute_perms_table_ent(State *state, size_t pos,
|
||||
}
|
||||
}
|
||||
|
||||
void DFA::compute_perms_table(vector <aa_perms> &perms_table)
|
||||
void DFA::compute_perms_table(vector <aa_perms> &perms_table, bool prompt)
|
||||
{
|
||||
size_t mult = filedfa ? 2 : 1;
|
||||
size_t pos = 2;
|
||||
@@ -1407,13 +1334,13 @@ void DFA::compute_perms_table(vector <aa_perms> &perms_table)
|
||||
perms_table.resize(states.size() * mult);
|
||||
|
||||
// nonmatching and start need to be 0 and 1 so handle outside of loop
|
||||
compute_perms_table_ent(nonmatching, 0, perms_table);
|
||||
compute_perms_table_ent(start, 1, perms_table);
|
||||
compute_perms_table_ent(nonmatching, 0, perms_table, prompt);
|
||||
compute_perms_table_ent(start, 1, perms_table, prompt);
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if (*i == nonmatching || *i == start)
|
||||
continue;
|
||||
compute_perms_table_ent(*i, pos, perms_table);
|
||||
compute_perms_table_ent(*i, pos, perms_table, prompt);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
@@ -1454,207 +1381,84 @@ static inline int diff_qualifiers(perm32_t perm1, perm32_t perm2)
|
||||
(perm1 & AA_EXEC_TYPE) != (perm2 & AA_EXEC_TYPE));
|
||||
}
|
||||
|
||||
/* update a single permission based on priority - only called if match->perm | match-> audit bit set */
|
||||
static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
|
||||
MatchFlag *match, perms_t &perms, perms_t &exact,
|
||||
bool filedfa)
|
||||
{
|
||||
// scaling priority *4
|
||||
int pri = match->priority<<2;
|
||||
|
||||
/* use priority to get proper ordering and application of the type
|
||||
* of match flag.
|
||||
*
|
||||
* Note: this is the last use of priority, it is dropped and not
|
||||
* used in the backend.
|
||||
*/
|
||||
if (match->is_type(NODE_TYPE_DENYMATCHFLAG))
|
||||
pri += 3;
|
||||
// exact match must be same priority as allow as its audit
|
||||
// flags has the same priority.
|
||||
// current no ALLOWMATCHFLAG it is just absence of other flags
|
||||
// so it has to be second last in this list, using !last
|
||||
// until this gets fixed
|
||||
else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG) ||
|
||||
(!match->is_type(NODE_TYPE_PROMPTMATCHFLAG)))
|
||||
pri += 2;
|
||||
else if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG))
|
||||
pri += 1;
|
||||
|
||||
if (priority[i] > pri) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " > " << pri << " SKIPPING " << hex << (match->perms) << "/" << (match->audit) << dec << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
perm32_t xmask = 0;
|
||||
perm32_t mask = 1 << i;
|
||||
perm32_t amask = mask;
|
||||
|
||||
// drop once we move the xindex out of the perms in the front end
|
||||
if (filedfa) {
|
||||
if (mask & AA_USER_EXEC) {
|
||||
xmask = AA_USER_EXEC_TYPE;
|
||||
// ix implies EXEC_MMAP
|
||||
if (match->perms & AA_EXEC_INHERIT) {
|
||||
xmask |= AA_USER_EXEC_MMAP;
|
||||
//USER_EXEC_MAP = 6
|
||||
if (priority[6] < pri)
|
||||
priority[6] = pri;
|
||||
}
|
||||
amask = mask | xmask;
|
||||
} else if (mask & AA_OTHER_EXEC) {
|
||||
xmask = AA_OTHER_EXEC_TYPE;
|
||||
// ix implies EXEC_MMAP
|
||||
if (match->perms & AA_OTHER_EXEC_INHERIT) {
|
||||
xmask |= AA_OTHER_EXEC_MMAP;
|
||||
//OTHER_EXEC_MAP = 20
|
||||
if (priority[20] < pri)
|
||||
priority[20] = pri;
|
||||
}
|
||||
amask = mask | xmask;
|
||||
} else if (((mask & AA_USER_EXEC_MMAP) &&
|
||||
(match->perms & AA_USER_EXEC_INHERIT)) ||
|
||||
((mask & AA_OTHER_EXEC_MMAP) &&
|
||||
(match->perms & AA_OTHER_EXEC_INHERIT))) {
|
||||
// if exec && ix we handled mmp above
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " SKIPPING mmap unmasked " << hex << match->perms << "/" << match->audit << " masked " << (match->perms & amask) << "/" << (match->audit & amask) << " data " << (perms.allow & mask) << "/" << (perms.audit & mask) << " exact " << (exact.allow & mask) << "/" << (exact.audit & mask) << dec << "\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " vs. " << pri << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n";
|
||||
if (priority[i] < pri) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << pri << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec;
|
||||
priority[i] = pri;
|
||||
perms.clear_bits(amask);
|
||||
exact.clear_bits(amask);
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << dec << "\n";
|
||||
}
|
||||
|
||||
// the if conditions in order of permission priority
|
||||
if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " deny " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n";
|
||||
perms.deny |= match->perms & amask;
|
||||
perms.quiet |= match->audit & amask;
|
||||
|
||||
perms.allow &= ~amask;
|
||||
perms.audit &= ~amask;
|
||||
perms.prompt &= ~amask;
|
||||
} else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
||||
/* exact match only asserts dominance on the XTYPE */
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " exact " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n";
|
||||
if (filedfa &&
|
||||
!is_merged_x_consistent(exact.allow, match->perms & amask)) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " exact match conflict" << "\n";
|
||||
return 1;
|
||||
}
|
||||
exact.allow |= match->perms & amask;
|
||||
exact.audit |= match->audit & amask;
|
||||
|
||||
// dominance is only done for XTYPE so only clear that
|
||||
// note xmask only set if setting x perm bit, so this
|
||||
// won't clear for other bit types
|
||||
perms.allow &= ~xmask;
|
||||
perms.audit &= ~xmask;
|
||||
perms.prompt &= ~xmask;
|
||||
|
||||
perms.allow |= match->perms & amask;
|
||||
perms.audit |= match->audit & amask;
|
||||
// can't specify exact prompt atm
|
||||
|
||||
} else if (!match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) {
|
||||
// allow perms, if exact has been encountered will already be set
|
||||
// if overlaps x here, don't conflict, because exact will override
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " allow " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n";
|
||||
if (filedfa && !(exact.allow & mask) &&
|
||||
!is_merged_x_consistent(perms.allow, match->perms & amask)) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " allow match conflict" << "\n";
|
||||
return 1;
|
||||
}
|
||||
// mask off if XTYPE in xmatch
|
||||
if ((exact.allow | exact.audit) & mask) {
|
||||
// mask == amask & ~xmask
|
||||
perms.allow |= match->perms & mask;
|
||||
perms.audit |= match->audit & mask;
|
||||
} else {
|
||||
perms.allow |= match->perms & amask;
|
||||
perms.audit |= match->audit & amask;
|
||||
}
|
||||
} else { // if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " prompt " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n";
|
||||
if (filedfa && !((exact.allow | perms.allow) & mask) &&
|
||||
!is_merged_x_consistent(perms.allow, match->perms & amask)) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " prompt match conflict" << "\n";
|
||||
return 1;
|
||||
}
|
||||
if ((exact.allow | exact.audit | perms.allow | perms.audit) & mask) {
|
||||
// mask == amask & ~xmask
|
||||
perms.prompt |= match->perms & mask;
|
||||
perms.audit |= match->audit & mask;
|
||||
} else {
|
||||
perms.prompt |= match->perms & amask;
|
||||
perms.audit |= match->audit & amask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the permission flags that this state corresponds to. If we
|
||||
* have any exact matches, then they override the execute and safe
|
||||
* execute flags.
|
||||
*/
|
||||
int accept_perms(optflags const &opts, NodeVec *state, perms_t &perms,
|
||||
bool filedfa)
|
||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
||||
{
|
||||
int error = 0;
|
||||
perms_t exact;
|
||||
// scaling priority by *4
|
||||
std::vector<int> priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY<<2); // 32 but wan't tied to perm32_t
|
||||
|
||||
perms.clear();
|
||||
|
||||
if (!state)
|
||||
return error;
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << "Building\n";
|
||||
|
||||
for (NodeVec::iterator i = state->begin(); i != state->end(); i++) {
|
||||
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
|
||||
continue;
|
||||
|
||||
MatchFlag *match = static_cast<MatchFlag *>(*i);
|
||||
if (perms.priority > match->priority)
|
||||
continue;
|
||||
|
||||
perm32_t bit = 1;
|
||||
perm32_t check = match->perms | match->audit;
|
||||
if (filedfa)
|
||||
check &= ~ALL_AA_EXEC_TYPE;
|
||||
|
||||
for (int i = 0; check; i++) {
|
||||
if (check & bit) {
|
||||
error = pri_update_perm(opts, priority, i, match, perms, exact, filedfa);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
check &= ~bit;
|
||||
bit <<= 1;
|
||||
if (perms.priority < match->priority) {
|
||||
perms.clear(match->priority);
|
||||
exact.clear(match->priority);
|
||||
}
|
||||
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
||||
/* exact match only ever happens with x */
|
||||
if (filedfa &&
|
||||
!is_merged_x_consistent(exact.allow, match->perms))
|
||||
error = 1;
|
||||
exact.allow |= match->perms;
|
||||
exact.audit |= match->audit;
|
||||
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||
perms.deny |= match->perms;
|
||||
perms.quiet |= match->audit;
|
||||
} else if (dynamic_cast<PromptMatchFlag *>(match)) {
|
||||
perms.prompt |= match->perms;
|
||||
perms.audit |= match->audit;
|
||||
} else {
|
||||
if (filedfa &&
|
||||
!is_merged_x_consistent(perms.allow, match->perms))
|
||||
error = 1;
|
||||
perms.allow |= match->perms;
|
||||
perms.audit |= match->audit;
|
||||
}
|
||||
}
|
||||
if (opts.dump & DUMP_DFA_PERMS) {
|
||||
cerr << " computed: "; perms.dump(cerr); cerr << "\n";
|
||||
|
||||
if (filedfa) {
|
||||
perms.allow |= exact.allow & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.prompt |= exact.prompt & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.audit |= exact.audit & ~(ALL_AA_EXEC_TYPE);
|
||||
} else {
|
||||
perms.allow |= exact.allow;
|
||||
perms.prompt |= exact.prompt;
|
||||
perms.audit |= exact.audit;
|
||||
}
|
||||
out:
|
||||
if (exact.allow & AA_USER_EXEC) {
|
||||
perms.allow = (exact.allow & AA_USER_EXEC_TYPE) |
|
||||
(perms.allow & ~AA_USER_EXEC_TYPE);
|
||||
perms.exact = AA_USER_EXEC_TYPE;
|
||||
}
|
||||
if (exact.allow & AA_OTHER_EXEC) {
|
||||
perms.allow = (exact.allow & AA_OTHER_EXEC_TYPE) |
|
||||
(perms.allow & ~AA_OTHER_EXEC_TYPE);
|
||||
perms.exact |= AA_OTHER_EXEC_TYPE;
|
||||
}
|
||||
if (filedfa && (AA_USER_EXEC & perms.deny))
|
||||
perms.deny |= AA_USER_EXEC_TYPE;
|
||||
|
||||
if (filedfa && (AA_OTHER_EXEC & perms.deny))
|
||||
perms.deny |= AA_OTHER_EXEC_TYPE;
|
||||
|
||||
perms.allow &= ~perms.deny;
|
||||
perms.quiet &= perms.deny;
|
||||
perms.prompt &= ~perms.deny;
|
||||
perms.prompt &= ~perms.allow;
|
||||
if (error)
|
||||
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
|
||||
|
||||
|
@@ -42,8 +42,8 @@ extern int prompt_compat_mode;
|
||||
|
||||
class State;
|
||||
|
||||
typedef std::map<transchar, State *> StateTrans;
|
||||
typedef std::list<State *> Partition;
|
||||
typedef map<transchar, State *> StateTrans;
|
||||
typedef list<State *> Partition;
|
||||
|
||||
#include "../immunix.h"
|
||||
|
||||
@@ -52,38 +52,37 @@ ostream &operator<<(ostream &os, State &state);
|
||||
|
||||
class perms_t {
|
||||
public:
|
||||
perms_t(void): allow(0), deny(0), prompt(0), audit(0), quiet(0), exact(0) { };
|
||||
perms_t(void): priority(MIN_INTERNAL_PRIORITY), allow(0), deny(0), prompt(0), audit(0), quiet(0), exact(0) { };
|
||||
|
||||
bool is_accept(void) { return (allow | deny | prompt | audit | quiet); }
|
||||
|
||||
void dump_header(ostream &os)
|
||||
{
|
||||
os << "(allow/deny/prompt/audit/quiet)";
|
||||
os << "priority (allow/deny/prompt/audit/quiet)";
|
||||
}
|
||||
ostream &dump(ostream &os)
|
||||
void dump(ostream &os)
|
||||
{
|
||||
os << "(0x " << std::hex
|
||||
os << " " << priority << " (0x " << hex
|
||||
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
|
||||
<< ')' << std::dec;
|
||||
return os;
|
||||
<< ')' << dec;
|
||||
}
|
||||
|
||||
void clear(void) {
|
||||
priority = MIN_INTERNAL_PRIORITY;
|
||||
allow = deny = prompt = audit = quiet = exact = 0;
|
||||
}
|
||||
|
||||
void clear_bits(perm32_t bits)
|
||||
{
|
||||
allow &= ~bits;
|
||||
deny &= ~bits;
|
||||
prompt &= ~bits;
|
||||
audit &= ~bits;
|
||||
quiet &= ~bits;
|
||||
exact &= ~bits;
|
||||
void clear(int p) {
|
||||
priority = p;
|
||||
allow = deny = prompt = audit = quiet = exact = 0;
|
||||
}
|
||||
|
||||
void add(perms_t &rhs, bool filedfa)
|
||||
{
|
||||
if (priority > rhs.priority)
|
||||
return;
|
||||
if (priority < rhs.priority) {
|
||||
*this = rhs;
|
||||
return;
|
||||
} //else if (rhs.priority == priority) {
|
||||
deny |= rhs.deny;
|
||||
|
||||
if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC,
|
||||
@@ -157,6 +156,8 @@ public:
|
||||
|
||||
bool operator<(perms_t const &rhs)const
|
||||
{
|
||||
if (priority < rhs.priority)
|
||||
return priority < rhs.priority;
|
||||
if (allow < rhs.allow)
|
||||
return allow < rhs.allow;
|
||||
if (deny < rhs.deny)
|
||||
@@ -168,11 +169,11 @@ public:
|
||||
return quiet < rhs.quiet;
|
||||
}
|
||||
|
||||
int priority;
|
||||
perm32_t allow, deny, prompt, audit, quiet, exact;
|
||||
};
|
||||
|
||||
int accept_perms(optflags const &opts, NodeVec *state, perms_t &perms,
|
||||
bool filedfa);
|
||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
|
||||
|
||||
/*
|
||||
* ProtoState - NodeSet and ancillery information used to create a state
|
||||
@@ -236,8 +237,7 @@ struct DiffDag {
|
||||
*/
|
||||
class State {
|
||||
public:
|
||||
State(optflags const &opts, int l, ProtoState &n, State *other,
|
||||
bool filedfa):
|
||||
State(int l, ProtoState &n, State *other, bool filedfa):
|
||||
label(l), flags(0), idx(0), perms(), trans()
|
||||
{
|
||||
int error;
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
proto = n;
|
||||
|
||||
/* Compute permissions associated with the State. */
|
||||
error = accept_perms(opts, n.anodes, perms, filedfa);
|
||||
error = accept_perms(n.anodes, perms, filedfa);
|
||||
if (error) {
|
||||
//cerr << "Failing on accept perms " << error << "\n";
|
||||
throw error;
|
||||
@@ -276,7 +276,7 @@ public:
|
||||
|
||||
ostream &dump(ostream &os)
|
||||
{
|
||||
os << *this << "\n";
|
||||
cerr << *this << "\n";
|
||||
for (StateTrans::iterator i = trans.begin(); i != trans.end(); i++) {
|
||||
os << " " << i->first.c << " -> " << *i->second << "\n";
|
||||
}
|
||||
@@ -289,10 +289,13 @@ public:
|
||||
|
||||
int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
|
||||
void map_perms_to_accept(perm32_t &accept1, perm32_t &accept2,
|
||||
perm32_t &accept3)
|
||||
perm32_t &accept3, bool prompt)
|
||||
{
|
||||
accept1 = perms.allow;
|
||||
accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet);
|
||||
if (prompt && prompt_compat_mode == PROMPT_COMPAT_DEV)
|
||||
accept2 = PACK_AUDIT_CTL(perms.prompt, perms.quiet);
|
||||
else
|
||||
accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet);
|
||||
accept3 = perms.prompt;
|
||||
}
|
||||
|
||||
@@ -314,16 +317,16 @@ public:
|
||||
class NodeMap: public CacheStats
|
||||
{
|
||||
public:
|
||||
typedef std::map<ProtoState, State *>::iterator iterator;
|
||||
typedef map<ProtoState, State *>::iterator iterator;
|
||||
iterator begin() { return cache.begin(); }
|
||||
iterator end() { return cache.end(); }
|
||||
|
||||
std::map<ProtoState, State *> cache;
|
||||
map<ProtoState, State *> cache;
|
||||
|
||||
NodeMap(void): cache() { };
|
||||
~NodeMap() override { clear(); };
|
||||
~NodeMap() { clear(); };
|
||||
|
||||
unsigned long size(void) const override { return cache.size(); }
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
@@ -331,10 +334,10 @@ public:
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
std::pair<iterator,bool> insert(ProtoState &proto, State *state)
|
||||
pair<iterator,bool> insert(ProtoState &proto, State *state)
|
||||
{
|
||||
std::pair<iterator,bool> uniq;
|
||||
uniq = cache.insert(std::make_pair(proto, state));
|
||||
pair<iterator,bool> uniq;
|
||||
uniq = cache.insert(make_pair(proto, state));
|
||||
if (uniq.second == false) {
|
||||
dup++;
|
||||
} else {
|
||||
@@ -346,18 +349,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<const State *, size_t> Renumber_Map;
|
||||
|
||||
/* Transitions in the DFA. */
|
||||
class DFA {
|
||||
void dump_node_to_dfa(void);
|
||||
State *add_new_state(optflags const &opts, NodeSet *nodes,
|
||||
State *other);
|
||||
State *add_new_state(optflags const &opts,NodeSet *anodes,
|
||||
NodeSet *nnodes, State *other);
|
||||
void update_state_transitions(optflags const &opts, State *state);
|
||||
State *add_new_state(NodeSet *nodes, State *other);
|
||||
State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other);
|
||||
void update_state_transitions(State *state);
|
||||
void process_work_queue(const char *header, optflags const &);
|
||||
void dump_diff_chain(ostream &os, std::map<State *, Partition> &relmap,
|
||||
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
|
||||
Partition &chain, State *state,
|
||||
unsigned int &count, unsigned int &total,
|
||||
unsigned int &max);
|
||||
@@ -366,17 +365,8 @@ class DFA {
|
||||
NodeVecCache anodes_cache;
|
||||
NodeVecCache nnodes_cache;
|
||||
NodeMap node_map;
|
||||
std::list<State *> work_queue;
|
||||
list<State *> work_queue;
|
||||
|
||||
void cleanup(void) {
|
||||
anodes_cache.clear();
|
||||
nnodes_cache.clear();
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
delete *i;
|
||||
}
|
||||
states.clear();
|
||||
}
|
||||
public:
|
||||
DFA(Node *root, optflags const &flags, bool filedfa);
|
||||
virtual ~DFA();
|
||||
@@ -395,18 +385,18 @@ public:
|
||||
void undiff_encode(void);
|
||||
void dump_diff_encode(ostream &os);
|
||||
|
||||
void dump(ostream &os, Renumber_Map *renum);
|
||||
void dump(ostream &os);
|
||||
void dump_dot_graph(ostream &os);
|
||||
void dump_uniq_perms(const char *s);
|
||||
ostream &dump_partition(ostream &os, Partition &p);
|
||||
ostream &dump_partitions(ostream &os, const char *description,
|
||||
std::list<Partition *> &partitions);
|
||||
std::map<transchar, transchar> equivalence_classes(optflags const &flags);
|
||||
void apply_equivalence_classes(std::map<transchar, transchar> &eq);
|
||||
|
||||
map<transchar, transchar> equivalence_classes(optflags const &flags);
|
||||
void apply_equivalence_classes(map<transchar, transchar> &eq);
|
||||
|
||||
void compute_perms_table_ent(State *state, size_t pos,
|
||||
std::vector <aa_perms> &perms_table);
|
||||
void compute_perms_table(std::vector <aa_perms> &perms_table);
|
||||
vector <aa_perms> &perms_table,
|
||||
bool prompt);
|
||||
void compute_perms_table(vector <aa_perms> &perms_table,
|
||||
bool prompt);
|
||||
|
||||
unsigned int diffcount;
|
||||
int oob_range;
|
||||
@@ -419,6 +409,6 @@ public:
|
||||
bool filedfa;
|
||||
};
|
||||
|
||||
void dump_equivalence_classes(ostream &os, std::map<transchar, transchar> &eq);
|
||||
void dump_equivalence_classes(ostream &os, map<transchar, transchar> &eq);
|
||||
|
||||
#endif /* __LIBAA_RE_HFA_H */
|
||||
|
@@ -24,8 +24,6 @@
|
||||
/* #define DEBUG_TREE */
|
||||
#include "expr-tree.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
@@ -62,7 +60,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b)
|
||||
%lex-param {YYLEX_PARAM}
|
||||
%parse-param {Node **root}
|
||||
%parse-param {const char *text}
|
||||
%define api.prefix {regex_}
|
||||
%name-prefix "regex_"
|
||||
|
||||
%token <c> CHAR
|
||||
%type <c> regex_char cset_char1 cset_char cset_charN
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user