mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 07:15:18 +00:00
Compare commits
145 Commits
fix-priori
...
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 |
16
.gitignore
vendored
16
.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
|
||||
|
129
.gitlab-ci.yml
129
.gitlab-ci.yml
@@ -4,40 +4,25 @@ 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
|
||||
|
||||
.ubuntu-common:
|
||||
.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
|
||||
@@ -50,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
|
||||
|
||||
@@ -84,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
|
||||
@@ -108,50 +93,31 @@ 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
|
||||
|
||||
# Build the regression tests (don't run them because that needs kernel access)
|
||||
test-build-regression:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# Additional dependencies required by regression tests
|
||||
- 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 attr fuse-overlayfs libdbus-1-dev liburing-dev
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
- make -C tests/regression/apparmor -j $(nproc)
|
||||
|
||||
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:
|
||||
@@ -173,26 +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
|
||||
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"
|
||||
|
@@ -8,7 +8,6 @@
|
||||
define DEBIAN_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
packages:
|
||||
- apache2-dev
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
@@ -16,14 +15,10 @@ packages:
|
||||
- bison
|
||||
- build-essential
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flake8
|
||||
- flex
|
||||
- fuse-overlayfs
|
||||
- gdb
|
||||
- gettext
|
||||
- libdbus-1-dev
|
||||
- libpam0g-dev
|
||||
- libtool
|
||||
- liburing-dev
|
||||
- pkg-config
|
||||
@@ -35,7 +30,6 @@ packages:
|
||||
- python3-tk
|
||||
- python3-ttkthemes
|
||||
- swig
|
||||
- toybox
|
||||
endef
|
||||
|
||||
# Ubuntu shares cloud-init profile with Debian.
|
||||
@@ -44,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
|
||||
@@ -55,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
|
||||
@@ -76,35 +62,7 @@ packages:
|
||||
- python3-setuptools
|
||||
- python3-tk
|
||||
- python311
|
||||
- python3-devel
|
||||
- python311-devel
|
||||
- swig
|
||||
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
|
||||
endef
|
||||
|
2
Makefile
2
Makefile
@@ -59,7 +59,7 @@ coverity: snapshot
|
||||
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
|
||||
|
26
README.md
26
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
|
||||
```
|
||||
|
||||
@@ -243,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
|
||||
```
|
||||
@@ -256,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
|
||||
```
|
||||
@@ -390,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 =
|
||||
|
@@ -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
|
@@ -309,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;
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1037,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
ret = get_profiles(fp, &profiles, &nprofiles);
|
||||
if (ret != 0) {
|
||||
eprintf(_("Failed to get profiles: %d....\n"), ret);
|
||||
eprintf("Failed to get profiles: %d....\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1068,7 +1066,7 @@ int main(int argc, char **argv)
|
||||
|
||||
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
||||
if (ret != 0) {
|
||||
eprintf(_("Failed to get 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);
|
||||
@@ -1094,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,165 +0,0 @@
|
||||
# Translations for aa_status
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2024.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 17:49-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
|
||||
#, c-format
|
||||
msgid "Error: failed to compile sub filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:715
|
||||
#, 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
|
||||
#, 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
|
||||
#, 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
|
||||
#, c-format
|
||||
msgid "Error: Invalid --help option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:924
|
||||
#, c-format
|
||||
msgid "Error: Invalid --show option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:946
|
||||
msgid "Error: Invalid command.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:971
|
||||
msgid "Error: Unknown options.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:983
|
||||
#, c-format
|
||||
msgid "Error: failed to compile mode filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:988
|
||||
#, c-format
|
||||
msgid "Error: failed to compile profiles filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:994
|
||||
#, c-format
|
||||
msgid "Error: failed to compile ps filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1000
|
||||
#, c-format
|
||||
msgid "Error: failed to compile exe filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1015
|
||||
#, 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
|
||||
msgid "Failed to parse json output"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1083
|
||||
msgid "Failed to print pretty json"
|
||||
msgstr ""
|
@@ -1 +1 @@
|
||||
4.1.0~beta1
|
||||
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);
|
||||
|
@@ -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
|
||||
|
@@ -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,206 +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
|
||||
static_assert(SWIG_NEWOBJ != 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
|
||||
|
||||
/* 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 an intmax_t because pid_t is guaranteed
|
||||
* to be a signed integer
|
||||
*/
|
||||
%typemap(in,noblock=1,fragment="SWIG_AsVal_long") pid_t (int conv_pid, intmax_t pid_large) {
|
||||
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 ((intmax_t) $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)
|
@@ -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 @@
|
||||
/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),
|
||||
}
|
||||
|
@@ -365,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})
|
||||
|
@@ -388,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
|
||||
@@ -604,7 +604,7 @@ modes:
|
||||
|
||||
=item B<Ux>
|
||||
|
||||
- unconfined execute -- use ld.so(8) secure-execution mode
|
||||
- unconfined execute -- scrub the environment
|
||||
|
||||
=item B<px>
|
||||
|
||||
@@ -612,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>
|
||||
|
||||
@@ -620,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>
|
||||
|
||||
@@ -632,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>
|
||||
|
||||
@@ -640,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>
|
||||
|
||||
@@ -648,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>
|
||||
|
||||
@@ -656,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>
|
||||
|
||||
@@ -715,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.
|
||||
@@ -743,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.
|
||||
|
||||
@@ -764,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.
|
||||
|
||||
@@ -788,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.
|
||||
@@ -1024,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:
|
||||
|
||||
@@ -1071,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:
|
||||
|
||||
@@ -1319,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,
|
||||
@@ -1339,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.
|
||||
@@ -1690,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,
|
||||
@@ -2159,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",
|
||||
|
@@ -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))
|
||||
|
||||
|
@@ -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)
|
||||
==============================================
|
||||
|
||||
|
@@ -259,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
|
||||
@@ -271,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);
|
||||
@@ -331,8 +331,6 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
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;
|
||||
|
@@ -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>
|
||||
@@ -594,11 +592,10 @@ void CHFA::weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
|
||||
// to repeat
|
||||
assert(accept.size() == old_base_size);
|
||||
accept.resize(accept.size() + file_chfa.accept.size());
|
||||
assert(policy_perms.size() < std::numeric_limits<ssize_t>::max());
|
||||
ssize_t size = (ssize_t) policy_perms.size();
|
||||
size_t size = policy_perms.size();
|
||||
policy_perms.resize(size*2 + file_perms.size());
|
||||
// shift and double the policy perms
|
||||
for (ssize_t i = size - 1; i >= 0; i--) {
|
||||
for (size_t i = size - 1; size >= 0; i--) {
|
||||
policy_perms[i*2] = policy_perms[i];
|
||||
policy_perms[i*2 + 1] = policy_perms[i];
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ class CHFA {
|
||||
DefaultBase default_base;
|
||||
NextCheck next_check;
|
||||
const State *start;
|
||||
Renumber_Map num;
|
||||
map<const State *, size_t> num;
|
||||
map<transchar, transchar> eq;
|
||||
unsigned int chfaflags;
|
||||
private:
|
||||
|
@@ -245,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 {
|
||||
@@ -916,10 +915,7 @@ 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) {}
|
||||
};
|
||||
|
||||
|
||||
|
@@ -83,21 +83,6 @@ ostream &operator<<(ostream &os, State &state)
|
||||
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
|
||||
@@ -317,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);
|
||||
@@ -326,7 +310,7 @@ State *DFA::add_new_state(optflags const &opts, NodeSet *anodes,
|
||||
|
||||
ProtoState proto;
|
||||
proto.init(nnodev, anodev);
|
||||
State *state = new State(opts, node_map.size(), proto, other, filedfa);
|
||||
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;
|
||||
@@ -338,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
|
||||
@@ -346,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
|
||||
@@ -374,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;
|
||||
|
||||
@@ -384,7 +367,7 @@ void DFA::update_state_transitions(optflags const &opts, State *state)
|
||||
*/
|
||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
||||
State *target;
|
||||
target = add_new_state(opts, j->second, nonmatching);
|
||||
target = add_new_state(j->second, nonmatching);
|
||||
|
||||
/* Don't insert transition that the otherwise transition
|
||||
* already covers
|
||||
@@ -431,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()) */
|
||||
}
|
||||
|
||||
@@ -461,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
|
||||
@@ -510,6 +493,11 @@ 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()
|
||||
@@ -558,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)
|
||||
{
|
||||
@@ -573,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +651,13 @@ int DFA::apply_and_clear_deny(void)
|
||||
return c;
|
||||
}
|
||||
|
||||
void DFA::clear_priorities(void)
|
||||
{
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
(*i)->perms.priority = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* minimize the number of dfa states */
|
||||
void DFA::minimize(optflags const &opts)
|
||||
@@ -1087,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);
|
||||
@@ -1114,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
|
||||
@@ -1122,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";
|
||||
@@ -1132,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
|
||||
@@ -1147,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";
|
||||
@@ -1393,186 +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)
|
||||
{
|
||||
if (priority[i] > match->priority) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " > " << match->priority << " 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] < match->priority)
|
||||
priority[6] = match->priority;
|
||||
}
|
||||
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] < match->priority)
|
||||
priority[20] = match->priority;
|
||||
}
|
||||
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] << " <= " << match->priority << " 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. " << match->priority << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n";
|
||||
if (priority[i] < match->priority) {
|
||||
if (opts.dump & DUMP_DFA_PERMS)
|
||||
cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << match->priority << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec;
|
||||
priority[i] = match->priority;
|
||||
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] << " <= " << match->priority << " 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] << " <= " << match->priority << " 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] << " <= " << match->priority << " 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] << " <= " << match->priority << " 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] << " <= " << match->priority << " 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] << " <= " << match->priority << " promt " << 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] << " <= " << match->priority << " 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;
|
||||
// size of vector needs to be number of bits in the data type
|
||||
// being used for the permission set.
|
||||
std::vector<int> priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY);
|
||||
|
||||
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");
|
||||
|
||||
|
@@ -52,37 +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)";
|
||||
}
|
||||
void dump(ostream &os)
|
||||
{
|
||||
os << "(0x " << hex
|
||||
os << " " << priority << " (0x " << hex
|
||||
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
|
||||
<< ')' << 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,
|
||||
@@ -156,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)
|
||||
@@ -167,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
|
||||
@@ -235,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;
|
||||
@@ -249,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;
|
||||
@@ -275,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";
|
||||
}
|
||||
@@ -348,16 +349,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef 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, map<State *, Partition> &relmap,
|
||||
Partition &chain, State *state,
|
||||
@@ -388,7 +385,7 @@ 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);
|
||||
|
||||
|
@@ -355,8 +355,7 @@ int is_valid_mnt_cond(const char *name, int src)
|
||||
static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
{
|
||||
unsigned int flags = 0, invflags = 0;
|
||||
if (inv)
|
||||
*inv = 0;
|
||||
*inv = 0;
|
||||
|
||||
struct value_list *entry, *tmp, *prev = NULL;
|
||||
list_for_each_safe(*list, entry, tmp) {
|
||||
@@ -369,7 +368,11 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
" => req: 0x%x inv: 0x%x\n",
|
||||
entry->value, mnt_opts_table[i].set,
|
||||
mnt_opts_table[i].clear, flags, invflags);
|
||||
list_remove_at(*list, prev, entry);
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *list)
|
||||
*list = tmp;
|
||||
entry->next = NULL;
|
||||
free_value_list(entry);
|
||||
} else
|
||||
prev = entry;
|
||||
@@ -680,7 +683,7 @@ int mnt_rule::cmp(rule_t const &rhs) const {
|
||||
return cmp_vec_int(opt_flagsv, rhs_mnt.opt_flagsv);
|
||||
}
|
||||
|
||||
static bool build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
@@ -690,8 +693,8 @@ static bool build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
/* all flags are optional */
|
||||
len = snprintf(p, size, "%s", default_match_pattern);
|
||||
if (len < 0 || len >= size)
|
||||
return false;
|
||||
return true;
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((opt_flags) & (1 << i))
|
||||
@@ -702,7 +705,7 @@ static bool build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
continue;
|
||||
|
||||
if (len < 0 || len >= size)
|
||||
return false;
|
||||
return FALSE;
|
||||
p += len;
|
||||
size -= len;
|
||||
}
|
||||
@@ -713,15 +716,15 @@ static bool build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
* like the empty string
|
||||
*/
|
||||
if (size < 9)
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
strcpy(p, "(\\xfe|)");
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
static int build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
{
|
||||
struct value_list *ent;
|
||||
pattern_t ptype;
|
||||
@@ -729,19 +732,19 @@ static bool build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
|
||||
if (!opts) {
|
||||
buffer.append(default_match_pattern);
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
list_for_each(opts, ent) {
|
||||
ptype = convert_aaregex_to_pcre(ent->value, 0, glob_default, buffer, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
if (ent->next)
|
||||
buffer.append(",");
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void mnt_rule::warn_once(const char *name)
|
||||
|
@@ -179,6 +179,8 @@ struct var_string {
|
||||
#define OPTION_STDOUT 4
|
||||
#define OPTION_OFILE 5
|
||||
|
||||
#define BOOL int
|
||||
|
||||
extern int preprocess_only;
|
||||
|
||||
#define PATH_CHROOT_REL 0x1
|
||||
@@ -211,6 +213,13 @@ do { \
|
||||
errno = perror_error; \
|
||||
} while (0)
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
#define MIN_PORT 0
|
||||
#define MAX_PORT 65535
|
||||
|
||||
@@ -242,6 +251,17 @@ do { \
|
||||
len; \
|
||||
})
|
||||
|
||||
#define list_find_prev(LIST, ENTRY) \
|
||||
({ \
|
||||
typeof(ENTRY) tmp, prev = NULL; \
|
||||
list_for_each((LIST), tmp) { \
|
||||
if (tmp == (ENTRY)) \
|
||||
break; \
|
||||
prev = tmp; \
|
||||
} \
|
||||
prev; \
|
||||
})
|
||||
|
||||
#define list_pop(LIST) \
|
||||
({ \
|
||||
typeof(LIST) _entry = (LIST); \
|
||||
@@ -259,6 +279,12 @@ do { \
|
||||
(LIST) = (ENTRY)->next; \
|
||||
(ENTRY)->next = NULL; \
|
||||
|
||||
#define list_remove(LIST, ENTRY) \
|
||||
do { \
|
||||
typeof(ENTRY) prev = list_find_prev((LIST), (ENTRY)); \
|
||||
list_remove_at((LIST), prev, (ENTRY)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define DUP_STRING(orig, new, field, fail_target) \
|
||||
do { \
|
||||
@@ -397,10 +423,10 @@ extern const char *basedir;
|
||||
#define glob_null 1
|
||||
extern pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
||||
std::string& pcre, int *first_re_pos);
|
||||
extern bool build_list_val_expr(std::string& buffer, struct value_list *list);
|
||||
extern bool convert_entry(std::string& buffer, char *entry);
|
||||
extern int build_list_val_expr(std::string& buffer, struct value_list *list);
|
||||
extern int convert_entry(std::string& buffer, char *entry);
|
||||
extern int clear_and_convert_entry(std::string& buffer, char *entry);
|
||||
extern bool convert_range(std::string& buffer, bignum start, bignum end);
|
||||
extern int convert_range(std::string& buffer, bignum start, bignum end);
|
||||
extern int process_regex(Profile *prof);
|
||||
extern int post_process_entry(struct cod_entry *entry);
|
||||
|
||||
@@ -419,6 +445,7 @@ extern void free_var_string(struct var_string *var);
|
||||
extern void warn_uppercase(void);
|
||||
extern int is_blacklisted(const char *name, const char *path);
|
||||
extern struct value_list *new_value_list(char *value);
|
||||
extern struct value_list *dup_value_list(struct value_list *list);
|
||||
extern void free_value_list(struct value_list *list);
|
||||
extern void print_value_list(struct value_list *list);
|
||||
extern struct cond_entry *new_cond_entry(char *name, int eq, struct value_list *list);
|
||||
|
@@ -142,10 +142,8 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
|
||||
}
|
||||
if (dup) {
|
||||
dup->alias_ignore = true;
|
||||
/* The original entry->next is in dup->next, so we don't lose
|
||||
* any of the original elements of the linked list. Also, by
|
||||
* setting dup->alias_ignore, we trigger the check at the start
|
||||
* of the loop, skipping the new entry we just inserted.
|
||||
/* adds to the front of the list, list iteratition
|
||||
* will skip it
|
||||
*/
|
||||
entry->next = dup;
|
||||
|
||||
|
@@ -202,7 +202,7 @@ static void start_include_position(const char *filename)
|
||||
current_lineno = 1;
|
||||
}
|
||||
|
||||
void push_include_stack(const char *filename)
|
||||
void push_include_stack(char *filename)
|
||||
{
|
||||
struct include_stack_t *include = NULL;
|
||||
|
||||
|
@@ -29,7 +29,7 @@ extern void parse_default_paths(void);
|
||||
extern int do_include_preprocessing(char *profilename);
|
||||
FILE *search_path(char *filename, char **fullpath, bool *skip);
|
||||
|
||||
extern void push_include_stack(const char *filename);
|
||||
extern void push_include_stack(char *filename);
|
||||
extern void pop_include_stack(void);
|
||||
extern void reset_include_stack(const char *filename);
|
||||
|
||||
|
@@ -245,7 +245,7 @@ static inline void sd_write_uint64(std::ostringstream &buf, u64 b)
|
||||
|
||||
static inline void sd_write_name(std::ostringstream &buf, const char *name)
|
||||
{
|
||||
PDEBUG("Writing name '%s'\n", name ? name : "(null)");
|
||||
PDEBUG("Writing name '%s'\n", name);
|
||||
if (name) {
|
||||
sd_write8(buf, SD_NAME);
|
||||
sd_write16(buf, strlen(name) + 1);
|
||||
|
@@ -1620,6 +1620,7 @@ int main(int argc, char *argv[])
|
||||
progname = argv[0];
|
||||
|
||||
init_base_dir();
|
||||
capabilities_init();
|
||||
|
||||
process_early_args(argc, argv);
|
||||
process_config_file(config_file);
|
||||
|
@@ -35,7 +35,6 @@
|
||||
#include <sys/apparmor_private.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "capability.h"
|
||||
#include "lib.h"
|
||||
@@ -62,10 +61,6 @@ void *reallocarray(void *ptr, size_t nmemb, size_t size)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL nullptr
|
||||
#endif
|
||||
|
||||
int is_blacklisted(const char *name, const char *path)
|
||||
{
|
||||
int retval = _aa_is_blacklisted(name);
|
||||
@@ -76,7 +71,12 @@ int is_blacklisted(const char *name, const char *path)
|
||||
return !retval ? 0 : 1;
|
||||
}
|
||||
|
||||
static const unordered_map<string, int> keyword_table = {
|
||||
struct keyword_table {
|
||||
const char *keyword;
|
||||
unsigned int token;
|
||||
};
|
||||
|
||||
static struct keyword_table keyword_table[] = {
|
||||
/* network */
|
||||
{"network", TOK_NETWORK},
|
||||
{"unix", TOK_UNIX},
|
||||
@@ -132,9 +132,11 @@ static const unordered_map<string, int> keyword_table = {
|
||||
{"sqpoll", TOK_SQPOLL},
|
||||
{"all", TOK_ALL},
|
||||
{"priority", TOK_PRIORITY},
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static const unordered_map<string, int> rlimit_table = {
|
||||
static struct keyword_table rlimit_table[] = {
|
||||
{"cpu", RLIMIT_CPU},
|
||||
{"fsize", RLIMIT_FSIZE},
|
||||
{"data", RLIMIT_DATA},
|
||||
@@ -160,33 +162,37 @@ static const unordered_map<string, int> rlimit_table = {
|
||||
#ifdef RLIMIT_RTTIME
|
||||
{"rttime", RLIMIT_RTTIME},
|
||||
#endif
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
/* for alpha matches, check for keywords */
|
||||
static int get_table_token(const char *name unused, const unordered_map<string, int> &table,
|
||||
const string &keyword)
|
||||
static int get_table_token(const char *name unused, struct keyword_table *table,
|
||||
const char *keyword)
|
||||
{
|
||||
auto token_entry = table.find(keyword);
|
||||
if (token_entry == table.end()) {
|
||||
PDEBUG("Unable to find %s %s\n", name, keyword.c_str());
|
||||
return -1;
|
||||
} else {
|
||||
PDEBUG("Found %s %s\n", name, keyword.c_str());
|
||||
return token_entry->second;
|
||||
int i;
|
||||
|
||||
for (i = 0; table[i].keyword; i++) {
|
||||
PDEBUG("Checking %s %s\n", name, table[i].keyword);
|
||||
if (strcmp(keyword, table[i].keyword) == 0) {
|
||||
PDEBUG("Found %s %s\n", name, table[i].keyword);
|
||||
return table[i].token;
|
||||
}
|
||||
}
|
||||
|
||||
PDEBUG("Unable to find %s %s\n", name, keyword);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for alpha matches, check for keywords */
|
||||
int get_keyword_token(const char *keyword)
|
||||
{
|
||||
// Can't use string_view because that requires C++17
|
||||
return get_table_token("keyword", keyword_table, string(keyword));
|
||||
return get_table_token("keyword", keyword_table, keyword);
|
||||
}
|
||||
|
||||
int get_rlimit(const char *name)
|
||||
{
|
||||
// Can't use string_view because that requires C++17
|
||||
return get_table_token("rlimit", rlimit_table, string(name));
|
||||
return get_table_token("rlimit", rlimit_table, name);
|
||||
}
|
||||
|
||||
|
||||
@@ -202,164 +208,55 @@ struct capability_table {
|
||||
capability_flags flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Enum for the results of adding a capability, with values assigned to match
|
||||
* the int values returned by the old capable_add_cap function:
|
||||
*
|
||||
* -1: error
|
||||
* 0: no change - capability already in table
|
||||
* 1: added flag to capability in table
|
||||
* 2: added new capability
|
||||
*/
|
||||
enum add_cap_result {
|
||||
ERROR = -1, // Was only used for OOM conditions
|
||||
ALREADY_EXISTS = 0,
|
||||
FLAG_ADDED = 1,
|
||||
CAP_ADDED = 2
|
||||
};
|
||||
|
||||
static struct capability_table base_capability_table[] = {
|
||||
/* capabilities */
|
||||
#include "cap_names.h"
|
||||
};
|
||||
static const size_t BASE_CAP_TABLE_SIZE = sizeof(base_capability_table)/sizeof(struct capability_table);
|
||||
|
||||
class capability_lookup {
|
||||
vector<capability_table> cap_table;
|
||||
// Use unordered_map to avoid pulling in two map implementations
|
||||
// We may want to switch to boost::multiindex to avoid duplication
|
||||
unordered_map<string, capability_table&> name_cap_map;
|
||||
unordered_map<unsigned int, capability_table&> int_cap_map;
|
||||
|
||||
private:
|
||||
void add_capability_table_entry_raw(capability_table entry) {
|
||||
cap_table.push_back(entry);
|
||||
capability_table &entry_ref = cap_table.back();
|
||||
name_cap_map.emplace(string(entry_ref.name), entry_ref);
|
||||
int_cap_map.emplace(entry_ref.cap, entry_ref);
|
||||
}
|
||||
public:
|
||||
capability_lookup() :
|
||||
cap_table(vector<capability_table>()),
|
||||
name_cap_map(unordered_map<string, capability_table&>(BASE_CAP_TABLE_SIZE)),
|
||||
int_cap_map(unordered_map<unsigned int, capability_table&>(BASE_CAP_TABLE_SIZE)) {
|
||||
cap_table.reserve(BASE_CAP_TABLE_SIZE);
|
||||
for (size_t i=0; i<BASE_CAP_TABLE_SIZE; i++) {
|
||||
add_capability_table_entry_raw(base_capability_table[i]);
|
||||
}
|
||||
}
|
||||
|
||||
capability_table* find_cap_entry_by_name(string const & name) const {
|
||||
auto map_entry = this->name_cap_map.find(name);
|
||||
if (map_entry == this->name_cap_map.end()) {
|
||||
return NULL;
|
||||
} else {
|
||||
PDEBUG("Found %s %s\n", name.c_str(), map_entry->second.name);
|
||||
return &map_entry->second;
|
||||
}
|
||||
}
|
||||
|
||||
capability_table* find_cap_entry_by_num(unsigned int cap) const {
|
||||
auto map_entry = this->int_cap_map.find(cap);
|
||||
if (map_entry == this->int_cap_map.end()) {
|
||||
return NULL;
|
||||
} else {
|
||||
PDEBUG("Found %d %d\n", cap, map_entry->second.cap);
|
||||
return &map_entry->second;
|
||||
}
|
||||
}
|
||||
|
||||
int name_to_capability(string const &cap) const {
|
||||
auto map_entry = this->name_cap_map.find(cap);
|
||||
if (map_entry == this->name_cap_map.end()) {
|
||||
PDEBUG("Unable to find %s %s\n", "capability", cap.c_str());
|
||||
return -1;
|
||||
} else {
|
||||
return map_entry->second.cap;
|
||||
}
|
||||
}
|
||||
|
||||
const char *capability_to_name(unsigned int cap) const {
|
||||
auto map_entry = this->int_cap_map.find(cap);
|
||||
if (map_entry == this->int_cap_map.end()) {
|
||||
return "invalid-capability";
|
||||
} else {
|
||||
return map_entry->second.name;
|
||||
}
|
||||
}
|
||||
|
||||
int capability_backmap(unsigned int cap) const {
|
||||
auto map_entry = this->int_cap_map.find(cap);
|
||||
if (map_entry == this->int_cap_map.end()) {
|
||||
return NO_BACKMAP_CAP;
|
||||
} else {
|
||||
return map_entry->second.backmap;
|
||||
}
|
||||
}
|
||||
|
||||
bool capability_in_kernel(unsigned int cap) const {
|
||||
auto map_entry = this->int_cap_map.find(cap);
|
||||
if (map_entry == this->int_cap_map.end()) {
|
||||
return false;
|
||||
} else {
|
||||
return map_entry->second.flags & CAPFLAG_KERNEL_FEATURE;
|
||||
}
|
||||
}
|
||||
|
||||
void __debug_capabilities(uint64_t capset, const char *name) const {
|
||||
printf("%s:", name);
|
||||
|
||||
for (auto it = this->cap_table.cbegin(); it != this->cap_table.cend(); it++) {
|
||||
if ((1ull << it->cap) & capset)
|
||||
printf (" %s", it->name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
add_cap_result capable_add_cap(string const & str, unsigned int cap,
|
||||
capability_flags flag) {
|
||||
struct capability_table *ent = this->find_cap_entry_by_name(str);
|
||||
if (ent) {
|
||||
if (ent->cap != cap) {
|
||||
pwarn(WARN_UNEXPECTED, "feature capability '%s:%d' does not equal expected %d. Ignoring ...\n", str.c_str(), cap, ent->cap);
|
||||
/* TODO: make warn to error config */
|
||||
return add_cap_result::ALREADY_EXISTS;
|
||||
}
|
||||
if (ent->flags & flag)
|
||||
return add_cap_result::ALREADY_EXISTS;
|
||||
ent->flags = (capability_flags) (ent->flags | flag);
|
||||
return add_cap_result::FLAG_ADDED;
|
||||
} else {
|
||||
struct capability_table new_entry;
|
||||
new_entry.name = strdup(str.c_str());
|
||||
if (!new_entry.name) {
|
||||
yyerror(_("Out of memory"));
|
||||
return add_cap_result::ERROR;
|
||||
}
|
||||
new_entry.cap = cap;
|
||||
new_entry.backmap = 0;
|
||||
new_entry.flags = flag;
|
||||
try {
|
||||
this->add_capability_table_entry_raw(new_entry);
|
||||
} catch (const std::bad_alloc &_e) {
|
||||
yyerror(_("Out of memory"));
|
||||
return add_cap_result::ERROR;
|
||||
}
|
||||
// TODO: exception catching for causes other than OOM
|
||||
return add_cap_result::CAP_ADDED;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_cap_flag(capability_flags flags)
|
||||
{
|
||||
for (auto it = this->cap_table.begin(); it != this->cap_table.end(); it++) {
|
||||
PDEBUG("Clearing capability flag for capability \"%s\"\n", it->name);
|
||||
it->flags = (capability_flags) (it->flags & ~flags);
|
||||
}
|
||||
}
|
||||
/* terminate */
|
||||
{NULL, 0, 0, CAPFLAGS_CLEAR}
|
||||
};
|
||||
|
||||
static capability_lookup cap_table;
|
||||
static struct capability_table *cap_table;
|
||||
static int cap_table_size;
|
||||
|
||||
void capabilities_init(void)
|
||||
{
|
||||
cap_table = (struct capability_table *) malloc(sizeof(base_capability_table));
|
||||
if (!cap_table)
|
||||
yyerror(_("Memory allocation error."));
|
||||
memcpy(cap_table, base_capability_table, sizeof(base_capability_table));
|
||||
cap_table_size = sizeof(base_capability_table)/sizeof(struct capability_table);
|
||||
}
|
||||
|
||||
struct capability_table *find_cap_entry_by_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; cap_table[i].name; i++) {
|
||||
PDEBUG("Checking %s %s\n", name, cap_table[i].name);
|
||||
if (strcmp(name, cap_table[i].name) == 0) {
|
||||
PDEBUG("Found %s %s\n", name, cap_table[i].name);
|
||||
return &cap_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct capability_table *find_cap_entry_by_num(unsigned int cap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; cap_table[i].name; i++) {
|
||||
PDEBUG("Checking %d %d\n", cap, cap_table[i].cap);
|
||||
if (cap == cap_table[i].cap) {
|
||||
PDEBUG("Found %d %d\n", cap, cap_table[i].cap);
|
||||
return &cap_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* don't mark up str with \0 */
|
||||
static const char *strn_token(const char *str, size_t &len)
|
||||
@@ -397,6 +294,59 @@ bool strcomp (const char *lhs, const char *rhs)
|
||||
return null_strcmp(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns: -1: error
|
||||
* 0: no change - capability already in table
|
||||
* 1: added flag to capability in table
|
||||
* 2: added new capability
|
||||
*/
|
||||
static int capable_add_cap(const char *str, int len, unsigned int cap,
|
||||
capability_flags flag)
|
||||
{
|
||||
/* extract name from str so we can treat as a string */
|
||||
autofree char *name = strndup(str, len);
|
||||
|
||||
if (!name) {
|
||||
yyerror(_("Out of memory"));
|
||||
return -1;
|
||||
}
|
||||
struct capability_table *ent = find_cap_entry_by_name(name);
|
||||
if (ent) {
|
||||
if (ent->cap != cap) {
|
||||
pwarn(WARN_UNEXPECTED, "feature capability '%s:%d' does not equal expected %d. Ignoring ...\n", name, cap, ent->cap);
|
||||
/* TODO: make warn to error config */
|
||||
return 0;
|
||||
}
|
||||
if (ent->flags & flag)
|
||||
return 0; /* no change */
|
||||
ent->flags = (capability_flags) (ent->flags | flag);
|
||||
return 1; /* modified */
|
||||
} else {
|
||||
struct capability_table *tmp;
|
||||
|
||||
tmp = (struct capability_table *) reallocarray(cap_table, sizeof(struct capability_table), cap_table_size+1);
|
||||
if (!tmp) {
|
||||
yyerror(_("Out of memory"));
|
||||
/* TODO: change away from yyerror */
|
||||
return -1;
|
||||
}
|
||||
cap_table = tmp;
|
||||
ent = &cap_table[cap_table_size - 1]; /* overwrite null */
|
||||
ent->name = strndup(name, len);
|
||||
if (!ent->name) {
|
||||
/* TODO: change away from yyerror */
|
||||
yyerror(_("Out of memory"));
|
||||
return -1;
|
||||
}
|
||||
ent->cap = cap;
|
||||
ent->flags = flag;
|
||||
cap_table[cap_table_size].name = NULL; /* new null */
|
||||
cap_table_size++;
|
||||
}
|
||||
|
||||
return 2; /* added */
|
||||
}
|
||||
|
||||
bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||
{
|
||||
autofree char *value = NULL;
|
||||
@@ -413,8 +363,7 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||
for (capstr = strn_token(value, len);
|
||||
capstr;
|
||||
capstr = strn_token(capstr + len, len)) {
|
||||
string capstr_as_str = string(capstr, len);
|
||||
if (cap_table.capable_add_cap(capstr_as_str, n, flags) < 0)
|
||||
if (capable_add_cap(capstr, len, n, flags) < 0)
|
||||
return false;
|
||||
n++;
|
||||
if (len > valuelen) {
|
||||
@@ -430,32 +379,70 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||
|
||||
void clear_cap_flag(capability_flags flags)
|
||||
{
|
||||
cap_table.clear_cap_flag(flags);
|
||||
int i;
|
||||
|
||||
for (i = 0; cap_table[i].name; i++) {
|
||||
PDEBUG("Clearing capability flag for capability \"%s\"\n", cap_table[i].name);
|
||||
cap_table[i].flags = (capability_flags) (cap_table[i].flags & ~flags);
|
||||
}
|
||||
}
|
||||
|
||||
int name_to_capability(const char *cap)
|
||||
{
|
||||
return cap_table.name_to_capability(string(cap));
|
||||
struct capability_table *ent;
|
||||
|
||||
ent = find_cap_entry_by_name(cap);
|
||||
if (ent)
|
||||
return ent->cap;
|
||||
|
||||
PDEBUG("Unable to find %s %s\n", "capability", cap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *capability_to_name(unsigned int cap)
|
||||
{
|
||||
return cap_table.capability_to_name(cap);
|
||||
struct capability_table *ent;
|
||||
|
||||
ent = find_cap_entry_by_num(cap);
|
||||
if (ent)
|
||||
return ent->name;
|
||||
|
||||
return "invalid-capability";
|
||||
}
|
||||
|
||||
int capability_backmap(unsigned int cap)
|
||||
{
|
||||
return cap_table.capability_backmap(cap);
|
||||
struct capability_table *ent;
|
||||
|
||||
ent = find_cap_entry_by_num(cap);
|
||||
if (ent)
|
||||
return ent->backmap;
|
||||
|
||||
return NO_BACKMAP_CAP;
|
||||
}
|
||||
|
||||
bool capability_in_kernel(unsigned int cap)
|
||||
{
|
||||
return cap_table.capability_in_kernel(cap);
|
||||
struct capability_table *ent;
|
||||
|
||||
ent = find_cap_entry_by_num(cap);
|
||||
if (ent)
|
||||
return ent->flags & CAPFLAG_KERNEL_FEATURE;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void __debug_capabilities(uint64_t capset, const char *name)
|
||||
{
|
||||
cap_table.__debug_capabilities(capset, name);
|
||||
unsigned int i;
|
||||
|
||||
printf("%s:", name);
|
||||
|
||||
for (i = 0; cap_table[i].name; i++) {
|
||||
if ((1ull << cap_table[i].cap) & capset)
|
||||
printf (" %s", cap_table[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
char *processunquoted(const char *string, int len)
|
||||
@@ -1213,6 +1200,37 @@ void free_value_list(struct value_list *list)
|
||||
}
|
||||
}
|
||||
|
||||
struct value_list *dup_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *entry, *dup, *head = NULL;
|
||||
char *value;
|
||||
|
||||
list_for_each(list, entry) {
|
||||
value = NULL;
|
||||
if (list->value) {
|
||||
value = strdup(list->value);
|
||||
if (!value)
|
||||
goto fail2;
|
||||
}
|
||||
dup = new_value_list(value);
|
||||
if (!dup)
|
||||
goto fail;
|
||||
if (head)
|
||||
list_append(head, dup);
|
||||
else
|
||||
head = dup;
|
||||
}
|
||||
|
||||
return head;
|
||||
|
||||
fail:
|
||||
free(value);
|
||||
fail2:
|
||||
free_value_list(head);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void print_value_list(struct value_list *list)
|
||||
{
|
||||
struct value_list *entry;
|
||||
|
@@ -50,7 +50,7 @@ enum error_type {
|
||||
void filter_slashes(char *path)
|
||||
{
|
||||
char *sptr, *dptr;
|
||||
bool seen_slash = false;
|
||||
BOOL seen_slash = 0;
|
||||
|
||||
if (!path || (strlen(path) < 2))
|
||||
return;
|
||||
@@ -69,7 +69,7 @@ void filter_slashes(char *path)
|
||||
++sptr;
|
||||
} else {
|
||||
*dptr++ = *sptr++;
|
||||
seen_slash = true;
|
||||
seen_slash = TRUE;
|
||||
}
|
||||
} else {
|
||||
seen_slash = 0;
|
||||
@@ -111,14 +111,14 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
||||
#define MAX_ALT_DEPTH 50
|
||||
*first_re_pos = 0;
|
||||
|
||||
int ret = 1;
|
||||
int ret = TRUE;
|
||||
/* flag to indicate input error */
|
||||
enum error_type error;
|
||||
|
||||
const char *sptr;
|
||||
pattern_t ptype;
|
||||
|
||||
bool bEscape = false; /* flag to indicate escape */
|
||||
BOOL bEscape = 0; /* flag to indicate escape */
|
||||
int ingrouping = 0; /* flag to indicate {} context */
|
||||
int incharclass = 0; /* flag to indicate [ ] context */
|
||||
int grouping_count[MAX_ALT_DEPTH] = {0};
|
||||
@@ -150,7 +150,7 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
||||
if (bEscape) {
|
||||
pcre.append("\\\\");
|
||||
} else {
|
||||
bEscape = true;
|
||||
bEscape = TRUE;
|
||||
++sptr;
|
||||
continue; /*skip turning bEscape off */
|
||||
} /* bEscape */
|
||||
@@ -393,7 +393,7 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
||||
break;
|
||||
} /* switch (*sptr) */
|
||||
|
||||
bEscape = false;
|
||||
bEscape = FALSE;
|
||||
++sptr;
|
||||
} /* while error == e_no_error && *sptr) */
|
||||
|
||||
@@ -419,12 +419,12 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob,
|
||||
PERROR(_("%s: Unable to parse input line '%s'\n"),
|
||||
progname, aare);
|
||||
|
||||
ret = 0;
|
||||
ret = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret == 0)
|
||||
if (ret == FALSE)
|
||||
ptype = ePatternInvalid;
|
||||
|
||||
if (parseopts.dump & DUMP_DFA_RULE_EXPR)
|
||||
@@ -464,7 +464,7 @@ static void warn_once_xattr(const char *name)
|
||||
common_warn_once(name, "xattr attachment conditional ignored", &warned_name);
|
||||
}
|
||||
|
||||
static bool process_profile_name_xmatch(Profile *prof)
|
||||
static int process_profile_name_xmatch(Profile *prof)
|
||||
{
|
||||
std::string tbuf;
|
||||
pattern_t ptype;
|
||||
@@ -479,7 +479,7 @@ static bool process_profile_name_xmatch(Profile *prof)
|
||||
/* don't filter_slashes for profile names, do on attachment */
|
||||
name = strdup(local_name(prof->name));
|
||||
if (!name)
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
filter_slashes(name);
|
||||
ptype = convert_aaregex_to_pcre(name, 0, glob_default, tbuf,
|
||||
@@ -491,7 +491,7 @@ static bool process_profile_name_xmatch(Profile *prof)
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!prof->attachment)
|
||||
@@ -506,11 +506,11 @@ static bool process_profile_name_xmatch(Profile *prof)
|
||||
/* build a dfa */
|
||||
aare_rules *rules = new aare_rules();
|
||||
if (!rules)
|
||||
return false;
|
||||
return FALSE;
|
||||
if (!rules->add_rule(tbuf.c_str(), 0, RULE_ALLOW,
|
||||
AA_MAY_EXEC, 0, parseopts)) {
|
||||
delete rules;
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
if (prof->altnames) {
|
||||
struct alt_name *alt;
|
||||
@@ -525,7 +525,7 @@ static bool process_profile_name_xmatch(Profile *prof)
|
||||
RULE_ALLOW, AA_MAY_EXEC,
|
||||
0, parseopts)) {
|
||||
delete rules;
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -567,7 +567,7 @@ static bool process_profile_name_xmatch(Profile *prof)
|
||||
&len);
|
||||
if (!rules->append_rule(tbuf.c_str(), true, true, parseopts)) {
|
||||
delete rules;
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,10 +581,10 @@ build:
|
||||
prof->xmatch = rules->create_dfablob(&prof->xmatch_size, &prof->xmatch_len, prof->xmatch_perms_table, parseopts, false, false, false);
|
||||
delete rules;
|
||||
if (!prof->xmatch)
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int warn_change_profile = 1;
|
||||
@@ -606,21 +606,21 @@ static bool is_change_profile_perms(perm32_t perms)
|
||||
return perms & AA_CHANGE_PROFILE;
|
||||
}
|
||||
|
||||
static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
{
|
||||
std::string tbuf;
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
|
||||
if (!entry) /* shouldn't happen */
|
||||
return false;
|
||||
return TRUE;
|
||||
|
||||
|
||||
if (!is_change_profile_perms(entry->perms))
|
||||
filter_slashes(entry->name);
|
||||
ptype = convert_aaregex_to_pcre(entry->name, 0, glob_default, tbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
entry->pattern_type = ptype;
|
||||
|
||||
@@ -649,13 +649,13 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
|
||||
entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0,
|
||||
parseopts))
|
||||
return false;
|
||||
return FALSE;
|
||||
} else if (!is_change_profile_perms(entry->perms)) {
|
||||
if (!dfarules->add_rule(tbuf.c_str(), entry->priority,
|
||||
entry->rule_mode, entry->perms,
|
||||
entry->audit == AUDIT_FORCE ? entry->perms : 0,
|
||||
parseopts))
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (entry->perms & (AA_LINK_BITS)) {
|
||||
@@ -669,7 +669,7 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
filter_slashes(entry->link_name);
|
||||
ptype = convert_aaregex_to_pcre(entry->link_name, 0, glob_default, lbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
if (entry->subset)
|
||||
perms |= LINK_TO_LINK_SUBSET(perms);
|
||||
vec[1] = lbuf.c_str();
|
||||
@@ -681,7 +681,7 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
entry->rule_mode, perms,
|
||||
entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0,
|
||||
2, vec, parseopts, false))
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
if (is_change_profile_perms(entry->perms)) {
|
||||
const char *vec[3];
|
||||
@@ -702,7 +702,7 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
if (entry->onexec) {
|
||||
ptype = convert_aaregex_to_pcre(entry->onexec, 0, glob_default, xbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
vec[0] = xbuf.c_str();
|
||||
} else
|
||||
/* allow change_profile for all execs */
|
||||
@@ -713,14 +713,14 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
|
||||
if (!parse_label(&stack, &ns, &name,
|
||||
tbuf.c_str(), false)) {
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (stack) {
|
||||
fprintf(stderr,
|
||||
_("The current kernel does not support stacking of named transitions: %s\n"),
|
||||
tbuf.c_str());
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ns)
|
||||
@@ -734,13 +734,13 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
|
||||
AA_CHANGE_PROFILE | onexec_perms,
|
||||
0, index - 1, &vec[1], parseopts, false))
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
/* onexec rules - both rules are needed for onexec */
|
||||
if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
|
||||
onexec_perms,
|
||||
0, 1, vec, parseopts, false))
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
/**
|
||||
* pick up any exec bits, from the frontend parser, related to
|
||||
@@ -750,19 +750,19 @@ static bool process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
|
||||
onexec_perms, 0, index, vec,
|
||||
parseopts, false))
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool post_process_entries(Profile *prof)
|
||||
int post_process_entries(Profile *prof)
|
||||
{
|
||||
int ret = true;
|
||||
int ret = TRUE;
|
||||
struct cod_entry *entry;
|
||||
|
||||
list_for_each(prof->entries, entry) {
|
||||
if (!process_dfa_entry(prof->dfa.rules, entry))
|
||||
ret = false;
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -815,7 +815,7 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
int build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
{
|
||||
struct value_list *ent;
|
||||
pattern_t ptype;
|
||||
@@ -823,7 +823,7 @@ bool build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
|
||||
if (!list) {
|
||||
buffer.append(default_match_pattern);
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
buffer.append("(");
|
||||
@@ -840,12 +840,12 @@ bool build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
}
|
||||
buffer.append(")");
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
fail:
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool convert_entry(std::string& buffer, char *entry)
|
||||
int convert_entry(std::string& buffer, char *entry)
|
||||
{
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
@@ -853,12 +853,12 @@ bool convert_entry(std::string& buffer, char *entry)
|
||||
if (entry) {
|
||||
ptype = convert_aaregex_to_pcre(entry, 0, glob_default, buffer, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
} else {
|
||||
buffer.append(default_match_pattern);
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int clear_and_convert_entry(std::string& buffer, char *entry)
|
||||
@@ -959,7 +959,7 @@ static std::string generate_regex_range(bignum start, bignum end)
|
||||
return result.str();
|
||||
}
|
||||
|
||||
bool convert_range(std::string& buffer, bignum start, bignum end)
|
||||
int convert_range(std::string& buffer, bignum start, bignum end)
|
||||
{
|
||||
pattern_t ptype;
|
||||
int pos;
|
||||
@@ -969,24 +969,24 @@ bool convert_range(std::string& buffer, bignum start, bignum end)
|
||||
if (!regex_range.empty()) {
|
||||
ptype = convert_aaregex_to_pcre(regex_range.c_str(), 0, glob_default, buffer, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return false;
|
||||
return FALSE;
|
||||
} else {
|
||||
buffer.append(default_match_pattern);
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool post_process_policydb_ents(Profile *prof)
|
||||
int post_process_policydb_ents(Profile *prof)
|
||||
{
|
||||
for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) {
|
||||
if ((*i)->skip())
|
||||
continue;
|
||||
if ((*i)->gen_policy_re(*prof) == RULE_ERROR)
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -79,7 +79,7 @@ struct var_string *split_out_var(const char *string)
|
||||
{
|
||||
struct var_string *n = NULL;
|
||||
const char *sptr;
|
||||
bool bEscape = false; /* flag to indicate escape */
|
||||
BOOL bEscape = 0; /* flag to indicate escape */
|
||||
|
||||
if (!string) /* shouldn't happen */
|
||||
return NULL;
|
||||
@@ -89,11 +89,15 @@ struct var_string *split_out_var(const char *string)
|
||||
while (!n && *sptr) {
|
||||
switch (*sptr) {
|
||||
case '\\':
|
||||
bEscape = !bEscape;
|
||||
if (bEscape) {
|
||||
bEscape = FALSE;
|
||||
} else {
|
||||
bEscape = TRUE;
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (bEscape) {
|
||||
bEscape = false;
|
||||
bEscape = FALSE;
|
||||
} else if (*(sptr + 1) == '{') {
|
||||
const char *eptr = get_var_end(sptr + 2);
|
||||
if (!eptr)
|
||||
@@ -107,7 +111,8 @@ struct var_string *split_out_var(const char *string)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bEscape = false;
|
||||
if (bEscape)
|
||||
bEscape = FALSE;
|
||||
}
|
||||
sptr++;
|
||||
}
|
||||
|
@@ -704,7 +704,7 @@ rules: rules opt_prefix block
|
||||
if (($2).priority != 0) {
|
||||
yyerror(_("priority is not allowed on rule blocks"));
|
||||
}
|
||||
PDEBUG("matched: %s%s%s%sblock\n",
|
||||
PDEBUG("matched: %s%s%sblock\n",
|
||||
$2.audit == AUDIT_FORCE ? "audit " : "",
|
||||
$2.rule_mode == RULE_DENY ? "deny " : "",
|
||||
$2.rule_mode == RULE_PROMPT ? "prompt " : "",
|
||||
|
@@ -1,14 +1,14 @@
|
||||
# Translations for apparmor_parser
|
||||
# Copyright (C) 2024 YEAR 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:55-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:51-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"
|
||||
@@ -86,41 +86,37 @@ msgid "Permission denied; attempted to load a profile while confined?\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:99 ../parser_interface.c:102 ../parser_interface.c:79
|
||||
#: ../parser_interface.c:82 ../parser_interface.c:84
|
||||
#: ../parser_interface.c:82
|
||||
#, c-format
|
||||
msgid "Unknown error (%d): %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:116 ../parser_interface.c:119 ../parser_interface.c:96
|
||||
#: ../parser_interface.c:100 ../parser_interface.c:102
|
||||
#: ../parser_interface.c:100
|
||||
#, c-format
|
||||
msgid "%s: Unable to add \"%s\". "
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:121 ../parser_interface.c:124
|
||||
#: ../parser_interface.c:101 ../parser_interface.c:105
|
||||
#: ../parser_interface.c:107
|
||||
#, c-format
|
||||
msgid "%s: Unable to replace \"%s\". "
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:126 ../parser_interface.c:129
|
||||
#: ../parser_interface.c:106 ../parser_interface.c:110
|
||||
#: ../parser_interface.c:112
|
||||
#, c-format
|
||||
msgid "%s: Unable to remove \"%s\". "
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:131 ../parser_interface.c:134
|
||||
#: ../parser_interface.c:111 ../parser_interface.c:115
|
||||
#: ../parser_interface.c:117
|
||||
#, c-format
|
||||
msgid "%s: Unable to write to stdout\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:135 ../parser_interface.c:138
|
||||
#: ../parser_interface.c:115 ../parser_interface.c:119
|
||||
#: ../parser_interface.c:121
|
||||
#, c-format
|
||||
msgid "%s: Unable to write to output file\n"
|
||||
msgstr ""
|
||||
@@ -129,28 +125,24 @@ msgstr ""
|
||||
#: ../parser_interface.c:141 ../parser_interface.c:165
|
||||
#: ../parser_interface.c:118 ../parser_interface.c:142
|
||||
#: ../parser_interface.c:123 ../parser_interface.c:147
|
||||
#: ../parser_interface.c:125 ../parser_interface.c:149
|
||||
#, c-format
|
||||
msgid "%s: ASSERT: Invalid option: %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:147 ../parser_interface.c:150
|
||||
#: ../parser_interface.c:127 ../parser_interface.c:132
|
||||
#: ../parser_interface.c:134
|
||||
#, c-format
|
||||
msgid "Addition succeeded for \"%s\".\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:151 ../parser_interface.c:154
|
||||
#: ../parser_interface.c:131 ../parser_interface.c:136
|
||||
#: ../parser_interface.c:138
|
||||
#, c-format
|
||||
msgid "Replacement succeeded for \"%s\".\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:155 ../parser_interface.c:158
|
||||
#: ../parser_interface.c:135 ../parser_interface.c:140
|
||||
#: ../parser_interface.c:142
|
||||
#, c-format
|
||||
msgid "Removal succeeded for \"%s\".\n"
|
||||
msgstr ""
|
||||
@@ -162,7 +154,6 @@ msgstr ""
|
||||
|
||||
#: ../parser_interface.c:656 ../parser_interface.c:658
|
||||
#: ../parser_interface.c:446 ../parser_interface.c:476
|
||||
#: ../parser_interface.c:542
|
||||
#, c-format
|
||||
msgid "profile %s network rules not enforced\n"
|
||||
msgstr ""
|
||||
@@ -208,18 +199,16 @@ msgstr ""
|
||||
|
||||
#: ../parser_interface.c:839 ../parser_interface.c:831
|
||||
#: ../parser_interface.c:593 ../parser_interface.c:579
|
||||
#: ../parser_interface.c:673
|
||||
#, c-format
|
||||
msgid "%s: Unable to write entire profile entry to cache\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:100 parser_lex.l:163 parser_lex.l:169 parser_lex.l:192
|
||||
#: parser_lex.l:100 parser_lex.l:163 parser_lex.l:169
|
||||
#, c-format
|
||||
msgid "Could not open '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:104 parser_lex.l:167 parser_lex.l:173 parser_lex.l:174
|
||||
#: parser_lex.l:197
|
||||
#, c-format
|
||||
msgid "fstat failed for '%s'"
|
||||
msgstr ""
|
||||
@@ -234,7 +223,7 @@ msgstr ""
|
||||
msgid "stat failed for '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:155 parser_lex.l:133 parser_lex.l:139 parser_lex.l:148
|
||||
#: parser_lex.l:155 parser_lex.l:133 parser_lex.l:139
|
||||
#, c-format
|
||||
msgid "Could not open '%s' in '%s'"
|
||||
msgstr ""
|
||||
@@ -246,7 +235,6 @@ msgid "Found unexpected character: '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:386 parser_lex.l:418 parser_lex.l:428 parser_lex.l:474
|
||||
#: parser_lex.l:516
|
||||
msgid "Variable declarations do not accept trailing commas"
|
||||
msgstr ""
|
||||
|
||||
@@ -266,7 +254,7 @@ msgid "%s: Could not allocate memory for subdomainbase mount point\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:577 ../parser_main.c:616 ../parser_main.c:479
|
||||
#: ../parser_main.c:1444 ../parser_main.c:1654
|
||||
#: ../parser_main.c:1444
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Warning: unable to find a suitable fs in %s, is it mounted?\n"
|
||||
@@ -282,7 +270,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:604 ../parser_main.c:642 ../parser_main.c:505
|
||||
#: ../parser_main.c:828 ../parser_main.c:891
|
||||
#: ../parser_main.c:828
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: Warning! You've set this program setuid root.\n"
|
||||
@@ -292,7 +280,6 @@ msgstr ""
|
||||
|
||||
#: ../parser_main.c:704 ../parser_main.c:813 ../parser_main.c:836
|
||||
#: ../parser_main.c:946 ../parser_main.c:860 ../parser_main.c:1038
|
||||
#: ../parser_main.c:1127
|
||||
#, c-format
|
||||
msgid "Error: Could not read profile %s: %s.\n"
|
||||
msgstr ""
|
||||
@@ -321,36 +308,29 @@ msgstr ""
|
||||
#: parser_yacc.y:1278 parser_yacc.y:1288 parser_yacc.y:1382 parser_yacc.y:1460
|
||||
#: parser_yacc.y:1592 parser_yacc.y:1597 parser_yacc.y:1674 parser_yacc.y:1692
|
||||
#: parser_yacc.y:1699 parser_yacc.y:1748 ../network.c:315 ../af_unix.cc:194
|
||||
#: ../parser_misc.c:226 ../parser_misc.c:970 parser_yacc.y:379
|
||||
#: parser_yacc.y:403 parser_yacc.y:571 parser_yacc.y:581 parser_yacc.y:673
|
||||
#: parser_yacc.y:744 parser_yacc.y:1073 parser_yacc.y:1160 parser_yacc.y:1169
|
||||
#: parser_yacc.y:1173 parser_yacc.y:1183 parser_yacc.y:1193 parser_yacc.y:1287
|
||||
#: parser_yacc.y:1365 parser_yacc.y:1561 parser_yacc.y:1569 parser_yacc.y:1619
|
||||
#: parser_yacc.y:1624 parser_yacc.y:1701 parser_yacc.y:1750 ../network.cc:899
|
||||
#: ../af_unix.cc:197 ../all_rule.cc:102 ../all_rule.cc:131
|
||||
msgid "Memory allocation error."
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:740 ../parser_main.c:872 ../parser_main.c:757
|
||||
#: ../parser_main.c:975 ../parser_main.c:1062
|
||||
#: ../parser_main.c:975
|
||||
#, c-format
|
||||
msgid "Cached load succeeded for \"%s\".\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:744 ../parser_main.c:876 ../parser_main.c:761
|
||||
#: ../parser_main.c:979 ../parser_main.c:1066
|
||||
#: ../parser_main.c:979
|
||||
#, c-format
|
||||
msgid "Cached reload succeeded for \"%s\".\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:910 ../parser_main.c:1058 ../parser_main.c:967
|
||||
#: ../parser_main.c:1132 ../parser_main.c:1221
|
||||
#: ../parser_main.c:1132
|
||||
#, c-format
|
||||
msgid "%s: Errors found in file. Aborting.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:426 ../parser_misc.c:597 ../parser_misc.c:339
|
||||
#: ../parser_misc.c:532 ../parser_misc.c:563
|
||||
#: ../parser_misc.c:532
|
||||
msgid ""
|
||||
"Uppercase qualifiers \"RWLIMX\" are deprecated, please convert to lowercase\n"
|
||||
"See the apparmor.d(5) manpage for details.\n"
|
||||
@@ -358,18 +338,17 @@ msgstr ""
|
||||
|
||||
#: ../parser_misc.c:467 ../parser_misc.c:474 ../parser_misc.c:638
|
||||
#: ../parser_misc.c:645 ../parser_misc.c:380 ../parser_misc.c:387
|
||||
#: ../parser_misc.c:573 ../parser_misc.c:580 ../parser_misc.c:604
|
||||
#: ../parser_misc.c:611
|
||||
#: ../parser_misc.c:573 ../parser_misc.c:580
|
||||
msgid "Conflict 'a' and 'w' perms are mutually exclusive."
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:491 ../parser_misc.c:662 ../parser_misc.c:404
|
||||
#: ../parser_misc.c:597 ../parser_misc.c:628
|
||||
#: ../parser_misc.c:597
|
||||
msgid "Exec qualifier 'i' invalid, conflicting qualifier already specified"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:502 ../parser_misc.c:673 ../parser_misc.c:415
|
||||
#: ../parser_misc.c:608 ../parser_misc.c:639
|
||||
#: ../parser_misc.c:608
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Unconfined exec qualifier (%c%c) allows some dangerous environment variables "
|
||||
@@ -378,16 +357,14 @@ msgstr ""
|
||||
|
||||
#: ../parser_misc.c:510 ../parser_misc.c:551 ../parser_misc.c:681
|
||||
#: ../parser_misc.c:722 ../parser_misc.c:423 ../parser_misc.c:464
|
||||
#: ../parser_misc.c:616 ../parser_misc.c:657 ../parser_misc.c:647
|
||||
#: ../parser_misc.c:688
|
||||
#: ../parser_misc.c:616 ../parser_misc.c:657
|
||||
#, c-format
|
||||
msgid "Exec qualifier '%c' invalid, conflicting qualifier already specified"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:537 ../parser_misc.c:545 ../parser_misc.c:708
|
||||
#: ../parser_misc.c:716 ../parser_misc.c:450 ../parser_misc.c:458
|
||||
#: ../parser_misc.c:643 ../parser_misc.c:651 ../parser_misc.c:674
|
||||
#: ../parser_misc.c:682
|
||||
#: ../parser_misc.c:643 ../parser_misc.c:651
|
||||
#, c-format
|
||||
msgid "Exec qualifier '%c%c' invalid, conflicting qualifier already specified"
|
||||
msgstr ""
|
||||
@@ -399,7 +376,7 @@ msgid "Internal: unexpected mode character '%c' in input"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:615 ../parser_misc.c:786 ../parser_misc.c:528
|
||||
#: ../parser_misc.c:721 ../parser_misc.c:752
|
||||
#: ../parser_misc.c:721
|
||||
#, c-format
|
||||
msgid "Internal error generated invalid perm 0x%llx\n"
|
||||
msgstr ""
|
||||
@@ -411,12 +388,12 @@ msgid "AppArmor parser error: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_merge.c:92 ../parser_merge.c:91 ../parser_merge.c:83
|
||||
#: ../parser_merge.c:71 ../parser_merge.c:74
|
||||
#: ../parser_merge.c:71
|
||||
msgid "Couldn't merge entries. Out of Memory\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_merge.c:111 ../parser_merge.c:113 ../parser_merge.c:105
|
||||
#: ../parser_merge.c:93 ../parser_merge.c:97
|
||||
#: ../parser_merge.c:93
|
||||
#, c-format
|
||||
msgid "profile %s: has merged rule %s with conflicting x modifiers\n"
|
||||
msgstr ""
|
||||
@@ -426,34 +403,28 @@ msgid "Profile attachment must begin with a '/'."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:260 parser_yacc.y:302 parser_yacc.y:348 parser_yacc.y:407
|
||||
#: parser_yacc.y:446
|
||||
msgid ""
|
||||
"Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:296 parser_yacc.y:338 parser_yacc.y:384 parser_yacc.y:449
|
||||
#: parser_yacc.y:487
|
||||
#, c-format
|
||||
msgid "Failed to create alias %s -> %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:417 parser_yacc.y:460 parser_yacc.y:506 parser_yacc.y:581
|
||||
#: ../profile.h:272
|
||||
msgid "Profile flag chroot_relative conflicts with namespace_relative"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:421 parser_yacc.y:464 parser_yacc.y:510 parser_yacc.y:585
|
||||
#: ../profile.h:276
|
||||
msgid "Profile flag mediate_deleted conflicts with delegate_deleted"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:424 parser_yacc.y:467 parser_yacc.y:513 parser_yacc.y:588
|
||||
#: ../profile.h:279
|
||||
msgid "Profile flag attach_disconnected conflicts with no_attach_disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:427 parser_yacc.y:470 parser_yacc.y:516 parser_yacc.y:591
|
||||
#: ../profile.h:282
|
||||
msgid "Profile flag chroot_attach conflicts with chroot_no_attach"
|
||||
msgstr ""
|
||||
|
||||
@@ -462,13 +433,12 @@ msgid "Profile flag 'debug' is no longer valid."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:463 parser_yacc.y:506 parser_yacc.y:552 parser_yacc.y:629
|
||||
#: ../profile.h:220
|
||||
#, c-format
|
||||
msgid "Invalid profile flag: %s."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:498 parser_yacc.y:520 parser_yacc.y:548 parser_yacc.y:594
|
||||
#: parser_yacc.y:673 parser_yacc.y:687
|
||||
#: parser_yacc.y:673
|
||||
msgid "Assert: `rule' returned NULL."
|
||||
msgstr ""
|
||||
|
||||
@@ -494,66 +464,55 @@ msgid "Assert: `network_rule' return invalid protocol."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:649 parser_yacc.y:696 parser_yacc.y:786 parser_yacc.y:867
|
||||
#: parser_yacc.y:776
|
||||
msgid "Assert: `change_profile' returned NULL."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:680 parser_yacc.y:720 parser_yacc.y:810 parser_yacc.y:905
|
||||
#: parser_yacc.y:814
|
||||
msgid "Assert: 'hat rule' returned NULL."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:689 parser_yacc.y:729 parser_yacc.y:819 parser_yacc.y:914
|
||||
#: parser_yacc.y:823
|
||||
msgid "Assert: 'local_profile rule' returned NULL."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:824 parser_yacc.y:885 parser_yacc.y:992 parser_yacc.y:1077
|
||||
#: ../cond_expr.cc:36
|
||||
#, c-format
|
||||
msgid "Unset boolean variable %s used in if-expression"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:882 parser_yacc.y:986 parser_yacc.y:1092 parser_yacc.y:1181
|
||||
#: parser_yacc.y:1083
|
||||
msgid "unsafe rule missing exec permissions"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:901 parser_yacc.y:954 parser_yacc.y:1060 parser_yacc.y:1148
|
||||
#: parser_yacc.y:1050
|
||||
msgid "subset can only be used with link rules."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:903 parser_yacc.y:956 parser_yacc.y:1062 parser_yacc.y:1150
|
||||
#: parser_yacc.y:1052
|
||||
msgid "link and exec perms conflict on a file rule using ->"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:905 parser_yacc.y:958 parser_yacc.y:1064 parser_yacc.y:1152
|
||||
#: parser_yacc.y:1054
|
||||
msgid "link perms are not allowed on a named profile transition.\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:921 parser_yacc.y:1003 parser_yacc.y:1109 parser_yacc.y:1198
|
||||
#: parser_yacc.y:1100
|
||||
#, c-format
|
||||
msgid "missing an end of line character? (entry: %s)"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:975 parser_yacc.y:985 parser_yacc.y:1057 parser_yacc.y:1067
|
||||
#: parser_yacc.y:1145 parser_yacc.y:1155 parser_yacc.y:1234 parser_yacc.y:1244
|
||||
#: ../network.cc:484
|
||||
msgid "Invalid network entry."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1039 parser_yacc.y:1048 parser_yacc.y:1254 parser_yacc.y:1510
|
||||
#: parser_yacc.y:1617 parser_yacc.y:1644
|
||||
#: parser_yacc.y:1617
|
||||
#, c-format
|
||||
msgid "Invalid capability %s."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1066 parser_yacc.y:1269 parser_yacc.y:1525 parser_yacc.y:1637
|
||||
#: parser_yacc.y:1664
|
||||
#, c-format
|
||||
msgid "AppArmor parser error for %s%s%s at line %d: %s\n"
|
||||
msgstr ""
|
||||
@@ -601,13 +560,13 @@ msgid "%s: Unable to parse input line '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_regex.c:397 ../parser_regex.c:405 ../parser_regex.c:421
|
||||
#: ../parser_regex.c:487 ../parser_regex.c:491
|
||||
#: ../parser_regex.c:487
|
||||
#, c-format
|
||||
msgid "%s: Invalid profile name '%s' - bad regular expression\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:202 ../parser_policy.c:402 ../parser_policy.c:375
|
||||
#: ../parser_policy.c:383 ../parser_policy.c:231
|
||||
#: ../parser_policy.c:383
|
||||
#, c-format
|
||||
msgid "ERROR merging rules for profile %s, failed to load\n"
|
||||
msgstr ""
|
||||
@@ -621,19 +580,19 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:279 ../parser_policy.c:359 ../parser_policy.c:332
|
||||
#: ../parser_policy.c:340 ../parser_policy.c:193
|
||||
#: ../parser_policy.c:340
|
||||
#, c-format
|
||||
msgid "ERROR processing regexs for profile %s, failed to load\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:306 ../parser_policy.c:389 ../parser_policy.c:362
|
||||
#: ../parser_policy.c:370 ../parser_policy.c:218
|
||||
#: ../parser_policy.c:370
|
||||
#, c-format
|
||||
msgid "ERROR expanding variables for profile %s, failed to load\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:390 ../parser_policy.c:382 ../parser_policy.c:355
|
||||
#: ../parser_policy.c:363 ../profile.cc:366
|
||||
#: ../parser_policy.c:363
|
||||
#, c-format
|
||||
msgid "ERROR adding hat access rule for profile %s\n"
|
||||
msgstr ""
|
||||
@@ -663,7 +622,7 @@ msgstr ""
|
||||
msgid "%s: Errors found in combining rules postprocessing. Aborting.\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:180 parser_lex.l:186 parser_lex.l:187 parser_lex.l:211
|
||||
#: parser_lex.l:180 parser_lex.l:186 parser_lex.l:187
|
||||
#, c-format
|
||||
msgid "Could not process include directory '%s' in '%s'"
|
||||
msgstr ""
|
||||
@@ -675,8 +634,6 @@ msgstr ""
|
||||
#: ../parser_main.c:1115 ../parser_main.c:1132 ../parser_main.c:1024
|
||||
#: ../parser_main.c:1041 ../parser_main.c:1332 ../parser_main.c:1354
|
||||
#: ../parser_misc.c:280 ../parser_misc.c:299 ../parser_misc.c:308
|
||||
#: ../parser_main.c:1511 ../parser_main.c:1535 ../parser_misc.c:310
|
||||
#: ../parser_misc.c:329 ../parser_misc.c:338
|
||||
msgid "Out of memory"
|
||||
msgstr ""
|
||||
|
||||
@@ -725,20 +682,20 @@ msgstr ""
|
||||
msgid "owner prefix not allow on capability rules"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1357 parser_yacc.y:1613 parser_yacc.y:1722 parser_yacc.y:1724
|
||||
#: parser_yacc.y:1357 parser_yacc.y:1613 parser_yacc.y:1722
|
||||
#, c-format
|
||||
msgid "invalid mount conditional %s%s"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1374 parser_yacc.y:1628 parser_yacc.y:1737 parser_yacc.y:1739
|
||||
#: parser_yacc.y:1374 parser_yacc.y:1628 parser_yacc.y:1737
|
||||
msgid "bad mount rule"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1381 parser_yacc.y:1635 parser_yacc.y:1744 parser_yacc.y:1746
|
||||
#: parser_yacc.y:1381 parser_yacc.y:1635 parser_yacc.y:1744
|
||||
msgid "mount point conditions not currently supported"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1398 parser_yacc.y:1650 parser_yacc.y:1759 parser_yacc.y:1761
|
||||
#: parser_yacc.y:1398 parser_yacc.y:1650 parser_yacc.y:1759
|
||||
#, c-format
|
||||
msgid "invalid pivotroot conditional '%s'"
|
||||
msgstr ""
|
||||
@@ -755,13 +712,11 @@ msgid "%s: Regex grouping error: Exceeded maximum nesting of {}\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:366 ../parser_policy.c:339 ../parser_policy.c:347
|
||||
#: ../parser_policy.c:200
|
||||
#, c-format
|
||||
msgid "ERROR processing policydb rules for profile %s, failed to load\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_policy.c:396 ../parser_policy.c:369 ../parser_policy.c:377
|
||||
#: ../parser_policy.c:225
|
||||
#, c-format
|
||||
msgid "ERROR replacing aliases for profile %s, failed to load\n"
|
||||
msgstr ""
|
||||
@@ -786,7 +741,7 @@ msgstr ""
|
||||
msgid "Internal: unexpected %s mode character '%c' in input"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:599 ../parser_misc.c:792 ../parser_misc.c:823
|
||||
#: ../parser_misc.c:599 ../parser_misc.c:792
|
||||
#, c-format
|
||||
msgid "Internal error generated invalid %s perm 0x%x\n"
|
||||
msgstr ""
|
||||
@@ -811,16 +766,16 @@ msgstr ""
|
||||
msgid "owner prefix not allowed on unix rules"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:794 parser_yacc.y:885 ../all_rule.cc:141
|
||||
#: parser_yacc.y:794 parser_yacc.y:885
|
||||
msgid "owner prefix not allowed on capability rules"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1293 parser_yacc.y:1377 parser_yacc.y:1282
|
||||
#: parser_yacc.y:1293 parser_yacc.y:1377
|
||||
#, c-format
|
||||
msgid "dbus rule: invalid conditional group %s=()"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1371 parser_yacc.y:1455 parser_yacc.y:1360
|
||||
#: parser_yacc.y:1371 parser_yacc.y:1455
|
||||
#, c-format
|
||||
msgid "unix rule: invalid conditional group %s=()"
|
||||
msgstr ""
|
||||
@@ -830,183 +785,183 @@ msgstr ""
|
||||
msgid "%s: Regex error: trailing '\\' escape character\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_common.c:112 ../parser_common.c:134
|
||||
#: ../parser_common.c:112
|
||||
#, c-format
|
||||
msgid "%s from %s (%s%sline %d): %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_common.c:113 ../parser_common.c:135
|
||||
#: ../parser_common.c:113
|
||||
msgid "Warning converted to Error"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_common.c:113 ../parser_common.c:135
|
||||
#: ../parser_common.c:113
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:524 ../parser_interface.c:618
|
||||
#: ../parser_interface.c:524
|
||||
#, c-format
|
||||
msgid "Unable to open stdout - %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:533 ../parser_interface.c:627
|
||||
#: ../parser_interface.c:533
|
||||
#, c-format
|
||||
msgid "Unable to open output file - %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:326 parser_lex.l:363
|
||||
#: parser_lex.l:326
|
||||
msgid "Failed to process filename\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:720 parser_lex.l:799
|
||||
#: parser_lex.l:720
|
||||
#, c-format
|
||||
msgid "Lexer found unexpected character: '%s' (0x%x) in state: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:915 ../parser_main.c:1002
|
||||
#: ../parser_main.c:915
|
||||
#, c-format
|
||||
msgid "Unable to print the cache directory: %m\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:951 ../parser_main.c:1038
|
||||
#: ../parser_main.c:951
|
||||
#, c-format
|
||||
msgid "Error: Could not load profile %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:961 ../parser_main.c:1048
|
||||
#: ../parser_main.c:961
|
||||
#, c-format
|
||||
msgid "Error: Could not replace profile %s: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:966 ../parser_main.c:1053
|
||||
#: ../parser_main.c:966
|
||||
#, c-format
|
||||
msgid "Error: Invalid load option specified: %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1077 ../parser_main.c:1166
|
||||
#: ../parser_main.c:1077
|
||||
#, c-format
|
||||
msgid "Could not get cachename for '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1434 ../parser_main.c:1644
|
||||
#: ../parser_main.c:1434
|
||||
msgid "Kernel features abi not found"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1438 ../parser_main.c:1648
|
||||
#: ../parser_main.c:1438
|
||||
msgid "Failed to add kernel capabilities to known capabilities set"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1465 ../parser_main.c:1675
|
||||
#: ../parser_main.c:1465
|
||||
#, c-format
|
||||
msgid "Failed to clear cache files (%s): %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1474 ../parser_main.c:1684
|
||||
#: ../parser_main.c:1474
|
||||
msgid ""
|
||||
"The --create-cache-dir option is deprecated. Please use --write-cache.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_main.c:1479 ../parser_main.c:1689
|
||||
#: ../parser_main.c:1479
|
||||
#, c-format
|
||||
msgid "Failed setting up policy cache (%s): %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:904 ../parser_misc.c:935
|
||||
#: ../parser_misc.c:904
|
||||
#, c-format
|
||||
msgid "Namespace not terminated: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:906 ../parser_misc.c:937
|
||||
#: ../parser_misc.c:906
|
||||
#, c-format
|
||||
msgid "Empty namespace: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:908 ../parser_misc.c:939
|
||||
#: ../parser_misc.c:908
|
||||
#, c-format
|
||||
msgid "Empty named transition profile name: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:910 ../parser_misc.c:941
|
||||
#: ../parser_misc.c:910
|
||||
#, c-format
|
||||
msgid "Unknown error while parsing label: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:306 parser_yacc.y:334
|
||||
#: parser_yacc.y:306
|
||||
msgid "Failed to setup default policy feature abi"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:308 parser_yacc.y:336
|
||||
#: parser_yacc.y:308
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: File '%s' missing feature abi, falling back to default policy feature "
|
||||
"abi\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:313 parser_yacc.y:341
|
||||
#: parser_yacc.y:313
|
||||
msgid "Failed to add policy capabilities to known capabilities set"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:350 parser_yacc.y:386
|
||||
#: parser_yacc.y:350
|
||||
msgid "Profile names must begin with a '/' or a namespace"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:372 parser_yacc.y:408
|
||||
#: parser_yacc.y:372
|
||||
msgid "Profile attachment must begin with a '/' or variable."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:375 parser_yacc.y:411
|
||||
#: parser_yacc.y:375
|
||||
#, c-format
|
||||
msgid "profile id: invalid conditional group %s=()"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:404 parser_yacc.y:443
|
||||
#: parser_yacc.y:404
|
||||
msgid ""
|
||||
"The use of file paths as profile names is deprecated. See man apparmor.d for "
|
||||
"more information\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:573 ../profile.h:264
|
||||
#: parser_yacc.y:573
|
||||
#, c-format
|
||||
msgid "Profile flag '%s' conflicts with '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:954 parser_yacc.y:862
|
||||
#: parser_yacc.y:954
|
||||
msgid "RLIMIT 'cpu' no units specified using default units of seconds\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:966 parser_yacc.y:874
|
||||
#: parser_yacc.y:966
|
||||
msgid ""
|
||||
"RLIMIT 'rttime' no units specified using default units of microseconds\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1582 parser_yacc.y:1609
|
||||
#: parser_yacc.y:1582
|
||||
msgid "Exec condition is required when unsafe or safe keywords are present"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1584 parser_yacc.y:1611
|
||||
#: parser_yacc.y:1584
|
||||
msgid "Exec condition must begin with '/'."
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1643 parser_yacc.y:1670
|
||||
#: parser_yacc.y:1643
|
||||
#, c-format
|
||||
msgid "AppArmor parser error at line %d: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1790 parser_yacc.y:1797
|
||||
#: parser_yacc.y:1790
|
||||
#, c-format
|
||||
msgid "Could not open '%s': %m"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1795 parser_yacc.y:1802
|
||||
#: parser_yacc.y:1795
|
||||
#, c-format
|
||||
msgid "fstat failed for '%s': %m"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1809 parser_yacc.y:1816
|
||||
#: parser_yacc.y:1809
|
||||
#, c-format
|
||||
msgid "failed to find features abi '%s': %m"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1813 parser_yacc.y:1821
|
||||
#: parser_yacc.y:1813
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: %s features abi '%s' differs from policy declared feature abi, using the "
|
||||
@@ -1018,124 +973,7 @@ msgstr ""
|
||||
msgid "%s: Invalid glob type %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_regex.c:693 ../parser_regex.c:721
|
||||
#: ../parser_regex.c:693
|
||||
#, c-format
|
||||
msgid "The current kernel does not support stacking of named transitions: %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:76
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: Permission denied. You need policy admin privileges to manage profiles.\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_interface.c:80
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: Access denied. You need policy admin privileges to manage profiles.\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: parser_lex.l:653 parser_lex.l:668
|
||||
msgid "deprecated use of '#include'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:730
|
||||
#, c-format
|
||||
msgid "Internal: unexpected perms character '%c' in input"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:799
|
||||
#, c-format
|
||||
msgid "Internal: unexpected %s perms character '%c' in input"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:1098
|
||||
msgid ""
|
||||
"Invalid perms, in deny rules 'x' must not be preceded by exec qualifier 'i', "
|
||||
"'p', or 'u'"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_misc.c:1102
|
||||
msgid "Invalid perms, 'x' must be preceded by exec qualifier 'i', 'p', or 'u'"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:689 parser_yacc.y:716 ../all_rule.cc:105 ../all_rule.cc:134
|
||||
#, c-format
|
||||
msgid "%s"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:705
|
||||
msgid "priority is not allowed on rule blocks"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:778
|
||||
msgid "owner conditional not allowed on unix rules"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:794
|
||||
msgid "owner conditional not allowed on capability rules"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1119 parser_yacc.y:1132 parser_yacc.y:1146
|
||||
#, c-format
|
||||
msgid "network rule: invalid conditional group %s=()"
|
||||
msgstr ""
|
||||
|
||||
#: parser_yacc.y:1827
|
||||
msgid "failed features abi not set but include cache skipped\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../parser_variable.c:295
|
||||
msgid "attach_disconnected_path value must begin with a /"
|
||||
msgstr ""
|
||||
|
||||
#: ../mount.cc:897
|
||||
msgid ""
|
||||
"The use of source as mount point for propagation type flags is deprecated.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../network.h:200
|
||||
msgid "priority prefix not allowed on network rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../network.h:204
|
||||
msgid "owner prefix not allowed on network rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../profile.h:287
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Profile flag attach_disconnected set to conflicting values: '%s' and '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: ../profile.h:297
|
||||
#, c-format
|
||||
msgid "Profile flag kill.signal set to conflicting values: '%d' and '%d'"
|
||||
msgstr ""
|
||||
|
||||
#: ../profile.h:307
|
||||
#, c-format
|
||||
msgid "Profile flag error set to conflicting values: '%s' and '%s'"
|
||||
msgstr ""
|
||||
|
||||
#: ../userns.h:36
|
||||
msgid "owner prefix not allowed on userns rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../mqueue.h:106
|
||||
msgid "owner prefix not allowed on mqueue rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../io_uring.h:42
|
||||
msgid "owner prefix not allowed on io_uring rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../all_rule.h:36
|
||||
msgid "priority prefix not allowed on all rules"
|
||||
msgstr ""
|
||||
|
||||
#: ../all_rule.h:40
|
||||
msgid "owner prefix not allowed on all rules"
|
||||
msgstr ""
|
||||
|
@@ -226,13 +226,13 @@ static bool add_proc_access(Profile *prof, const char *rule)
|
||||
char *buffer = strdup("/proc/*/attr/apparmor/");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
@@ -240,13 +240,13 @@ static bool add_proc_access(Profile *prof, const char *rule)
|
||||
buffer = strdup("/sys/module/apparmor/parameters/enabled");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
@@ -254,17 +254,17 @@ static bool add_proc_access(Profile *prof, const char *rule)
|
||||
buffer = strdup(rule);
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return false;
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
return true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
|
||||
|
@@ -363,7 +363,7 @@ public:
|
||||
struct cond_entry_list xattrs;
|
||||
|
||||
/* char *sub_name; */ /* subdomain name or NULL */
|
||||
/* bool default_deny; */
|
||||
/* int default_deny; */ /* TRUE or FALSE */
|
||||
bool local;
|
||||
|
||||
Profile *parent;
|
||||
|
@@ -253,7 +253,7 @@ remove_profiles() {
|
||||
retval=0
|
||||
# We filter child profiles as removing the parent will remove
|
||||
# the children
|
||||
sed -e "s/ (\(enforce\|complain\|prompt\|kill\|unconfined\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
sed -e "s/ (\(enforce\|complain\|unconfined\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
LC_COLLATE=C sort | grep -v // | {
|
||||
while read -r profile ; do
|
||||
printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
|
||||
|
@@ -182,8 +182,6 @@ public:
|
||||
{
|
||||
bool output = true;
|
||||
|
||||
if (priority != 0)
|
||||
os << "priority=" << priority << " ";
|
||||
switch (audit) {
|
||||
case AUDIT_FORCE:
|
||||
os << "audit";
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
@@ -35,7 +35,7 @@
|
||||
#define MAXRT_SIG 32 /* Max RT above MINRT_SIG */
|
||||
|
||||
/* Signal names mapped to and internal ordering */
|
||||
static unordered_map<string, int> signal_map = {
|
||||
static struct signal_map { const char *name; int num; } signal_map[] = {
|
||||
{"hup", 1},
|
||||
{"int", 2},
|
||||
{"quit", 3},
|
||||
@@ -55,8 +55,7 @@ static unordered_map<string, int> signal_map = {
|
||||
{"chld", 17},
|
||||
{"cont", 18},
|
||||
{"stop", 19},
|
||||
{"stp", 20}, // parser's previous name for SIGTSTP
|
||||
{"tstp", 20},
|
||||
{"stp", 20},
|
||||
{"ttin", 21},
|
||||
{"ttou", 22},
|
||||
{"urg", 23},
|
||||
@@ -65,12 +64,14 @@ static unordered_map<string, int> signal_map = {
|
||||
{"vtalrm", 26},
|
||||
{"prof", 27},
|
||||
{"winch", 28},
|
||||
{"io", 29}, // SIGIO == SIGPOLL
|
||||
{"poll", 29},
|
||||
{"io", 29},
|
||||
{"pwr", 30},
|
||||
{"sys", 31},
|
||||
{"emt", 32},
|
||||
{"exists", 35},
|
||||
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
/* this table is ordered post sig_map[sig] mapping */
|
||||
@@ -95,7 +96,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
"chld",
|
||||
"cont",
|
||||
"stop",
|
||||
"tstp",
|
||||
"stp",
|
||||
"ttin",
|
||||
"ttou",
|
||||
"urg",
|
||||
@@ -104,7 +105,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
"vtalrm",
|
||||
"prof",
|
||||
"winch",
|
||||
"io", // SIGIO == SIGPOLL
|
||||
"io",
|
||||
"pwr",
|
||||
"sys",
|
||||
"emt",
|
||||
@@ -129,14 +130,12 @@ int find_signal_mapping(const char *sig)
|
||||
return -1;
|
||||
return MINRT_SIG + n;
|
||||
} else {
|
||||
// Can't use string_view because that requires C++17
|
||||
auto sigmap = signal_map.find(string(sig));
|
||||
if (sigmap != signal_map.end()) {
|
||||
return sigmap->second;
|
||||
} else {
|
||||
return -1;
|
||||
for (int i = 0; signal_map[i].name; i++) {
|
||||
if (strcmp(sig, signal_map[i].name) == 0)
|
||||
return signal_map[i].num;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void signal_rule::extract_sigs(struct value_list **list)
|
||||
|
@@ -6,7 +6,7 @@ PARSER_BIN=apparmor_parser
|
||||
PARSER=$(PARSER_DIR)/$(PARSER_BIN)
|
||||
# parser.conf to use in tests. Note that some test scripts have the parser options hardcoded, so passing PARSER_ARGS=... is not enough to override it.
|
||||
PARSER_ARGS=--config-file=./parser.conf
|
||||
PROVE_ARG=-f --directives -j2
|
||||
PROVE_ARG=-f --directives
|
||||
|
||||
ifeq ($(VERBOSE),1)
|
||||
PROVE_ARG+=-v
|
||||
@@ -37,11 +37,6 @@ error_output: $(PARSER)
|
||||
parser_sanity: $(PARSER) gen_xtrans gen_dbus
|
||||
$(Q)LANG=C APPARMOR_PARSER="$(PARSER)" ${PROVE} ${PROVE_ARG} ${TESTS}
|
||||
|
||||
# use this target for faster manual testing if you don't want/need to test all the profiles generated by gen-*.py
|
||||
parser_sanity-no-gen: clean $(PARSER)
|
||||
@echo WARNING: not creating the profiles using the gen-*.py scripts
|
||||
$(Q)LANG=C APPARMOR_PARSER="$(PARSER)" ${PROVE} ${PROVE_ARG} ${TESTS}
|
||||
|
||||
caching: $(PARSER)
|
||||
LANG=C ./caching.py -p "$(PARSER)" $(PYTEST_ARG)
|
||||
|
||||
|
@@ -725,7 +725,7 @@ else
|
||||
|
||||
#this one may not be true in the future depending on if the compiled profile
|
||||
#is explicitly including deny permissions for dynamic composition
|
||||
verify_binary_equality "'$p1'x'$p2' Deny of ungranted perm" \
|
||||
verify_binary_inequality "'$p1'x'$p2' Deny of ungranted perm" \
|
||||
"/t { $p1 /foo/[abc] r, audit deny /foo/b w, }" \
|
||||
"/t { $p2 /foo/[abc] r, }"
|
||||
fi
|
||||
@@ -823,7 +823,7 @@ if { priority_lt "$p1" "" && priority_lt "$p2" "" ; } ||
|
||||
"/t { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, ^test { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, /f r, }}" \
|
||||
"/t { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, /f r, }}"
|
||||
else
|
||||
verify_binary_equality "'$p1'x'$p2' change_hat rules automatically inserted"\
|
||||
verify_binary_inequality "'$p1'x'$p2' change_hat rules automatically inserted"\
|
||||
"/t { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, ^test { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, /f r, }}" \
|
||||
"/t { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, /f r, }}"
|
||||
fi
|
||||
|
@@ -78,7 +78,7 @@ APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
|
||||
# {a} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles basic perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 6 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -93,7 +93,7 @@ echo "ok"
|
||||
# {9} (0x 12804a/0/2800a/0)
|
||||
# {c} (0x 40030/0/0/0)
|
||||
echo -n "Minimize profiles audit perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 6 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -112,7 +112,7 @@ echo "ok"
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles deny perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 6 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -130,7 +130,7 @@ echo "ok"
|
||||
# {c} (0x 40030/0/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 5 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 5 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -155,7 +155,7 @@ echo "ok"
|
||||
## NOTE: change count from 6 to 7 when extend perms is not dependent on
|
||||
## prompt rules being present
|
||||
echo -n "Minimize profiles extended no-filter audit deny perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 7 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 7 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -173,7 +173,7 @@ echo "ok"
|
||||
# {2} (0x 4/0//0/0/0) <- from policydb still showing up bug
|
||||
|
||||
echo -n "Minimize profiles extended filter audit deny perms "
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 6 ] ; then
|
||||
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -208,7 +208,7 @@ echo "ok"
|
||||
#
|
||||
|
||||
echo -n "Minimize profiles xtrans "
|
||||
if [ "$(echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 3 ] ; then
|
||||
if [ "$(echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -216,7 +216,7 @@ echo "ok"
|
||||
|
||||
# same test as above + audit
|
||||
echo -n "Minimize profiles audit xtrans "
|
||||
if [ "$(echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 3 ] ; then
|
||||
if [ "$(echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 3 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -229,7 +229,7 @@ echo "ok"
|
||||
# {3} (0x 0/fe17f85/0/14005)
|
||||
|
||||
echo -n "Minimize profiles deny xtrans "
|
||||
if [ "$(echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 1 ] ; then
|
||||
if [ "$(echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 1 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
@@ -241,7 +241,7 @@ echo "ok"
|
||||
# {3} (0x 0/fe17f85/0/0)
|
||||
|
||||
echo -n "Minimize profiles audit deny xtrans "
|
||||
if [ "$(echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*}(.*)$')" -ne 0 ] ; then
|
||||
if [ "$(echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 0 ] ; then
|
||||
echo "failed"
|
||||
exit 1;
|
||||
fi
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - missing end of range
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network port=22-,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - missing end of range
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network peer=(port=2222-),
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - spaces in range not allowed
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network port=22 - 443,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - spaces in range not allowed
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network peer=(port=22 - 443),
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - invalid "--"
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network port=22--443,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - invalid "--"
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network peer=(port=22--443),
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - 3 items in range
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network port=22-443-1024,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - 3 items in range
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network peer=(port=22-443-1024),
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - additional spaces
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network port = 22-443 ,
|
||||
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
#
|
||||
#=DESCRIPTION network port range conditional test - additional spaces
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
network peer=( port = 22-443 ),
|
||||
|
||||
}
|
@@ -98,11 +98,12 @@ class AATestTemplate(unittest.TestCase, metaclass=AANoCleanupMetaClass):
|
||||
except OSError as e:
|
||||
return 127, str(e), ''
|
||||
|
||||
timeout_communicate = TimeoutFunction(sp.communicate, timeout)
|
||||
out, outerr = (None, None)
|
||||
try:
|
||||
out, outerr = sp.communicate(input, timeout)
|
||||
out, outerr = timeout_communicate(input)
|
||||
rc = sp.returncode
|
||||
except subprocess.TimeoutExpired:
|
||||
except TimeoutFunctionException:
|
||||
sp.terminate()
|
||||
outerr = 'test timed out, killed'
|
||||
rc = TIMEOUT_ERROR_CODE
|
||||
@@ -116,6 +117,31 @@ class AATestTemplate(unittest.TestCase, metaclass=AANoCleanupMetaClass):
|
||||
|
||||
return rc, out, outerr
|
||||
|
||||
|
||||
# Timeout handler using alarm() from John P. Speno's Pythonic Avocado
|
||||
class TimeoutFunctionException(Exception):
|
||||
"""Exception to raise on a timeout"""
|
||||
|
||||
|
||||
class TimeoutFunction:
|
||||
def __init__(self, function, timeout):
|
||||
self.timeout = timeout
|
||||
self.function = function
|
||||
|
||||
def handle_timeout(self, signum, frame):
|
||||
raise TimeoutFunctionException()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
old = signal.signal(signal.SIGALRM, self.handle_timeout)
|
||||
signal.alarm(self.timeout)
|
||||
try:
|
||||
result = self.function(*args, **kwargs)
|
||||
finally:
|
||||
signal.signal(signal.SIGALRM, old)
|
||||
signal.alarm(0)
|
||||
return result
|
||||
|
||||
|
||||
def filesystem_time_resolution():
|
||||
"""detect whether the filesystem stores subsecond timestamps"""
|
||||
|
||||
|
@@ -154,12 +154,11 @@ check-logprof: test-dependencies
|
||||
|
||||
.PHONY: check-abstractions.d
|
||||
check-abstractions.d:
|
||||
@echo "*** Checking if all abstractions (with a few exceptions) contain 'include if exists <abstractions/*.d>' and 'abi <abi/4.0>,'"
|
||||
@echo "*** Checking if all abstractions (with a few exceptions) contain 'include if exists <abstractions/*.d>'"
|
||||
$(Q)for file in $$(find ${ABSTRACTIONS_SOURCE} ${EXTRAS_ABSTRACTIONS_SOURCE} -maxdepth 1 -type f) ; do \
|
||||
case "$${file}" in */ubuntu-browsers | */ubuntu-helpers) continue ;; esac ; \
|
||||
include="include if exists <abstractions/$$(basename $${file}).d>" ; \
|
||||
grep -q "^ $${include}\$$" $${file} || { echo "$${file} does not contain '$${include}'"; exit 1; } ; \
|
||||
grep -q "^ *abi <abi/4.0>," $${file} || { echo "$${file} does not contain 'abi <abi/4.0>,'"; exit 1; } ; \
|
||||
done
|
||||
|
||||
.PHONY: check-tunables.d
|
||||
@@ -173,10 +172,9 @@ check-tunables.d:
|
||||
|
||||
.PHONY: check-local
|
||||
check-local:
|
||||
@echo "*** Checking if all profiles contain 'include if exists <local/*>' and 'abi <abi/4.0>,'"
|
||||
@echo "*** Checking if all profiles contain 'include if exists <local/*>'"
|
||||
$(Q)for file in $$(find ${PROFILES_SOURCE} ${EXTRAS_SOURCE} -maxdepth 1 -type f) ; do \
|
||||
case "$${file}" in */README) continue ;; esac ; \
|
||||
include="include if exists <local/$$(basename $${file})>" ; \
|
||||
grep -q "^ *$${include}\$$" $${file} || { echo "$${file} does not contain '$${include}'"; exit 1; } ; \
|
||||
grep -q "^ *abi <abi/4.0>," $${file} || { echo "$${file} does not contain 'abi <abi/4.0>,'"; exit 1; } ; \
|
||||
done
|
||||
|
@@ -10,8 +10,6 @@
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
# Note: executing groff and nroff themself is not included in this abstraction
|
||||
# so that you can choose to ix, Px or Cx them in your profile
|
||||
|
||||
|
@@ -42,6 +42,9 @@
|
||||
# have open
|
||||
@{run}/nscd/db* mix,
|
||||
|
||||
# make libnss-libvirt name resolution work.
|
||||
/var/lib/libvirt/dnsmasq/* r,
|
||||
|
||||
# make libnss-libvirt name resolution work.
|
||||
/var/lib/libvirt/dnsmasq/ r,
|
||||
/var/lib/libvirt/dnsmasq/*.status r,
|
||||
|
@@ -13,19 +13,19 @@
|
||||
abi <abi/4.0>,
|
||||
|
||||
/{usr/,}bin/ r,
|
||||
/{usr/,}bin/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]} r,
|
||||
/{usr/,}bin/python{2.[4-7],3,3.[0-9],3.1[0-9]} r,
|
||||
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{pyc,so,so.*[0-9]} mr,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{egg,py,pth} r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/ r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/**/ r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.dist-info/{METADATA,namespace_packages.txt} r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.VERSION r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/*.egg-info/PKG-INFO r,
|
||||
/usr/{local/,}lib{,32,64}/python{3.[0-9],3.[1-9][0-9]}/lib-dynload/*.so mr,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/**.{pyc,so,so.*[0-9]} mr,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/**.{egg,py,pth} r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/ r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/**/ r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/*.dist-info/{METADATA,namespace_packages.txt} r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/*.VERSION r,
|
||||
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/*.egg-info/PKG-INFO r,
|
||||
/usr/{local/,}lib{,32,64}/python3.{1,}[0-9]/lib-dynload/*.so mr,
|
||||
|
||||
# Site-wide configuration
|
||||
/etc/python{2.[4-7],3.[0-9],3.[1-9][0-9]}/** r,
|
||||
/etc/python{2.[4-7],3.[0-9],3.1[0-9]}/** r,
|
||||
|
||||
# shared python paths
|
||||
/usr/share/{pyshared,pycentral,python-support}/** r,
|
||||
@@ -38,12 +38,12 @@
|
||||
/usr/lib/wx/python/*.pth r,
|
||||
|
||||
# python build configuration and headers
|
||||
/usr/include/python{2.[4-7],3.[0-9],3.[1-9][0-9]}*/pyconfig.h r,
|
||||
/usr/include/python{2.[4-7],3.[0-9],3.1[0-9]}*/pyconfig.h r,
|
||||
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{pyc,so} mr,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{egg,py,pth} r,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/ r,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/**/ r,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.1[0-9]}/**.{pyc,so} mr,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.1[0-9]}/**.{egg,py,pth} r,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/ r,
|
||||
owner @{HOME}/.local/lib/python{2.[4-7],3,3.[0-9],3.1[0-9]}/{site,dist}-packages/**/ r,
|
||||
|
||||
# Starting with Python 3.8, you can use the PYTHONPYCACHEPREFIX environment
|
||||
# variable to define a cache directory for Python.
|
||||
|
@@ -1,5 +1,3 @@
|
||||
abi <abi/4.0>,
|
||||
|
||||
profile snap_browsers {
|
||||
include if exists <abstractions/snap_browsers.d>
|
||||
include <abstractions/base>
|
||||
|
@@ -2,8 +2,6 @@
|
||||
# LOGPROF-SUGGEST: no
|
||||
# Author: Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
include <abstractions/base>
|
||||
include <abstractions/freedesktop.org>
|
||||
include <abstractions/nameservice>
|
||||
|
@@ -1,37 +0,0 @@
|
||||
#------------------------------------------------------------------
|
||||
# Copyright (C) 2024 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile tar /usr/bin/tar {
|
||||
include <abstractions/base>
|
||||
|
||||
# used to extract user files as root
|
||||
capability chown,
|
||||
|
||||
# used to compress user files as root
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
|
||||
file rwl /**,
|
||||
|
||||
# tar can be made to filter archives through an arbitrary program
|
||||
/{usr{/local,},}/{bin,sbin}/* ix,
|
||||
/opt/** ix,
|
||||
|
||||
# tar can compress/extract files over rsh/ssh
|
||||
network stream ip=127.0.0.1,
|
||||
network stream ip=::1,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/tar>
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile toybox /usr/bin/toybox flags=(unconfined) {
|
||||
profile toybox /bin/toybox flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user