mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
Compare commits
168 Commits
v4.0.0-bet
...
v2.11.2
Author | SHA1 | Date | |
---|---|---|---|
|
5afe0f8889 | ||
|
9c7e71358c | ||
|
d39706edf7 | ||
|
0e8d4e09f8 | ||
|
1765cbdc15 | ||
|
bee5ed218a | ||
|
be0fdfb03c | ||
|
ccc744b9ff | ||
|
8bba589d2d | ||
|
9c9b79faed | ||
|
3c53ad55df | ||
|
68b8bbeada | ||
|
509f56e22c | ||
|
52c3b487d0 | ||
|
a91c1e4329 | ||
|
e4fc384ae2 | ||
|
002fda8718 | ||
|
e5a72e8efb | ||
|
eaa7f03064 | ||
|
904536f7cf | ||
|
8248e01591 | ||
|
18d8ffe41e | ||
|
69d3d71cd9 | ||
|
299953ab7b | ||
|
2b447d3fce | ||
|
c8ca044d28 | ||
|
108e8afe6b | ||
|
1bb6223de4 | ||
|
4f8eaf8782 | ||
|
3e527d903f | ||
|
72232e0919 | ||
|
7c6a592ceb | ||
|
b0f55894f8 | ||
|
70ecff9962 | ||
|
8a32ae5143 | ||
|
cdaf5075cb | ||
|
9fb21a702c | ||
|
d55d99cbf1 | ||
|
e07ec63313 | ||
|
09050a8a8b | ||
|
5260be0518 | ||
|
7bf4f3a9a0 | ||
|
9af6d0ec0c | ||
|
b631b209f5 | ||
|
d1dd46d767 | ||
|
f6b497dd0c | ||
|
0e79f739be | ||
|
b8063e3342 | ||
|
660de9d4c3 | ||
|
d0ffb0fb48 | ||
|
a055c41207 | ||
|
582479235f | ||
|
4b178140d5 | ||
|
eb5f435c78 | ||
|
2fa87eb12e | ||
|
0a4a66a014 | ||
|
6c889d3a35 | ||
|
ca5386c09e | ||
|
65c7a474e7 | ||
|
4a817d423b | ||
|
ae4e230b05 | ||
|
0ce15469ec | ||
|
c0328fc460 | ||
|
64b8fdaa52 | ||
|
46fd2b39d1 | ||
|
ed2090a875 | ||
|
68d8fc0df7 | ||
|
cb37d500df | ||
|
44094c6514 | ||
|
1dc9f297e6 | ||
|
3350d482fe | ||
|
7d3c022651 | ||
|
fe621b37c4 | ||
|
c5bec9c0b5 | ||
|
9962cee942 | ||
|
6c81024701 | ||
|
ccc86d8036 | ||
|
e82683d3f5 | ||
|
b1e19b7563 | ||
|
6e068f9e25 | ||
|
9f0d4cb5b4 | ||
|
84b9b46fb0 | ||
|
11770f1702 | ||
|
93922246df | ||
|
ae29fb0749 | ||
|
a90e1eda2b | ||
|
39399257ea | ||
|
fdde7c9f74 | ||
|
aabcfa51d8 | ||
|
46ef60e979 | ||
|
3bdb7b1754 | ||
|
c0786268f3 | ||
|
b40e1eefbd | ||
|
e66ecb79e5 | ||
|
236c851bfe | ||
|
892d113ba4 | ||
|
65c010ccc3 | ||
|
2fdc5ca603 | ||
|
872d3f3bc2 | ||
|
54725ee516 | ||
|
4a76852648 | ||
|
c78752911e | ||
|
7f074b6677 | ||
|
1fe48e09dd | ||
|
fa1d2a1fc1 | ||
|
5e6948d2f9 | ||
|
4184b0c363 | ||
|
d97a8034fc | ||
|
41f29cbe1c | ||
|
1a3c0cd277 | ||
|
6cb59226bf | ||
|
2997b7d912 | ||
|
6ffe9f5fda | ||
|
8518a39a4b | ||
|
14ce11f608 | ||
|
2b7313cdd2 | ||
|
0ecc171de9 | ||
|
d4218f6ca4 | ||
|
d7bbfeee53 | ||
|
e9287e066b | ||
|
1872c52c6d | ||
|
da42248a95 | ||
|
fca085a352 | ||
|
2d0ab611b2 | ||
|
8316d34b2b | ||
|
bfbda33038 | ||
|
b4310a9366 | ||
|
67be2e9e9b | ||
|
d1da150d97 | ||
|
16c83927c0 | ||
|
535b3074ab | ||
|
50b7db4e3d | ||
|
f993585e77 | ||
|
728f02bf3c | ||
|
831c93294f | ||
|
89f3fb70a2 | ||
|
a29704b445 | ||
|
90e086986d | ||
|
0eedfe8319 | ||
|
8b81fe065f | ||
|
a8f5b8f0db | ||
|
878ebd4b33 | ||
|
bc5634f2af | ||
|
7c217b7413 | ||
|
86037e0a23 | ||
|
1f82a98029 | ||
|
7adbc4b3ee | ||
|
5199e44ef0 | ||
|
32e76985c9 | ||
|
54bdfd3565 | ||
|
bd68cd2d69 | ||
|
f076497f89 | ||
|
5089a941c8 | ||
|
3b490f9450 | ||
|
66928660f5 | ||
|
d2fc6ff1cc | ||
|
39fc9dc40f | ||
|
a90238e7c6 | ||
|
5246203c9e | ||
|
4b99f16b49 | ||
|
7777b1418e | ||
|
9d5934f5ff | ||
|
962d4afb3d | ||
|
eb8acf4b45 | ||
|
8217eb04af | ||
|
26e1200324 | ||
|
4181b187c3 | ||
|
485798c4f8 |
55
.gitignore
vendored
55
.gitignore
vendored
@@ -4,18 +4,10 @@ binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-load
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
binutils/po/*.mo
|
||||
parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
parser/generated_cap_names.h
|
||||
parser/generated_af_names.h
|
||||
parser/tst_lib
|
||||
parser/tst_misc
|
||||
parser/tst_regex
|
||||
@@ -29,10 +21,8 @@ parser/parser_yacc.h
|
||||
parser/pod2htm*.tmp
|
||||
parser/af_rule.o
|
||||
parser/af_unix.o
|
||||
parser/all_rule.o
|
||||
parser/common_optarg.o
|
||||
parser/dbus.o
|
||||
parser/default_features.o
|
||||
parser/lib.o
|
||||
parser/libapparmor_re/aare_rules.o
|
||||
parser/libapparmor_re/chfa.o
|
||||
@@ -41,7 +31,6 @@ parser/libapparmor_re/hfa.o
|
||||
parser/libapparmor_re/libapparmor_re.a
|
||||
parser/libapparmor_re/parse.o
|
||||
parser/mount.o
|
||||
parser/mqueue.o
|
||||
parser/network.o
|
||||
parser/parser_alias.o
|
||||
parser/parser_common.o
|
||||
@@ -61,8 +50,6 @@ parser/profile.o
|
||||
parser/ptrace.o
|
||||
parser/rule.o
|
||||
parser/signal.o
|
||||
parser/userns.o
|
||||
parser/io_uring.o
|
||||
parser/*.7
|
||||
parser/*.5
|
||||
parser/*.8
|
||||
@@ -165,7 +152,6 @@ libraries/libapparmor/swig/perl/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/perl/libapparmor_wrap.o
|
||||
libraries/libapparmor/swig/perl/pm_to_blib
|
||||
libraries/libapparmor/swig/python/LibAppArmor.py
|
||||
libraries/libapparmor/swig/python/LibAppArmor.egg-info/
|
||||
libraries/libapparmor/swig/python/build/
|
||||
libraries/libapparmor/swig/python/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/python/Makefile
|
||||
@@ -177,14 +163,8 @@ libraries/libapparmor/swig/python/test/test-suite.log
|
||||
libraries/libapparmor/swig/python/test/test_python.py
|
||||
libraries/libapparmor/swig/python/test/test_python.py.log
|
||||
libraries/libapparmor/swig/python/test/test_python.py.trs
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor.so
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor_wrap.c
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor_wrap.o
|
||||
libraries/libapparmor/swig/ruby/Makefile
|
||||
libraries/libapparmor/swig/ruby/Makefile.in
|
||||
libraries/libapparmor/swig/ruby/Makefile.bak
|
||||
libraries/libapparmor/swig/ruby/Makefile.ruby
|
||||
libraries/libapparmor/swig/ruby/mkmf.log
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
libraries/libapparmor/testsuite/.libs
|
||||
libraries/libapparmor/testsuite/Makefile
|
||||
@@ -210,22 +190,14 @@ utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
utils/test/coverage-report.txt
|
||||
utils/test/htmlcov/
|
||||
utils/vim/apparmor.vim
|
||||
utils/vim/apparmor.vim.5
|
||||
utils/vim/apparmor.vim.5.html
|
||||
utils/vim/pod2htmd.tmp
|
||||
tests/regression/apparmor/*.o
|
||||
tests/regression/apparmor/aa_policy_cache
|
||||
tests/regression/apparmor/access
|
||||
tests/regression/apparmor/at_secure
|
||||
tests/regression/apparmor/attach_disconnected
|
||||
tests/regression/apparmor/changehat
|
||||
tests/regression/apparmor/changehat_fail
|
||||
tests/regression/apparmor/changehat_fork
|
||||
@@ -240,10 +212,6 @@ tests/regression/apparmor/chgrp
|
||||
tests/regression/apparmor/chmod
|
||||
tests/regression/apparmor/chown
|
||||
tests/regression/apparmor/clone
|
||||
tests/regression/apparmor/dbus_eavesdrop
|
||||
tests/regression/apparmor/dbus_message
|
||||
tests/regression/apparmor/dbus_service
|
||||
tests/regression/apparmor/dbus_unrequested_reply
|
||||
tests/regression/apparmor/deleted
|
||||
tests/regression/apparmor/env_check
|
||||
tests/regression/apparmor/environ
|
||||
@@ -254,40 +222,26 @@ tests/regression/apparmor/fchdir
|
||||
tests/regression/apparmor/fchgrp
|
||||
tests/regression/apparmor/fchmod
|
||||
tests/regression/apparmor/fchown
|
||||
tests/regression/apparmor/fd_inheritance
|
||||
tests/regression/apparmor/fd_inheritor
|
||||
tests/regression/apparmor/fork
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/io_uring
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/mkdir
|
||||
tests/regression/apparmor/mmap
|
||||
tests/regression/apparmor/mount
|
||||
tests/regression/apparmor/move_mount
|
||||
tests/regression/apparmor/named_pipe
|
||||
tests/regression/apparmor/net_finegrained_rcv
|
||||
tests/regression/apparmor/net_finegrained_snd
|
||||
tests/regression/apparmor/net_raw
|
||||
tests/regression/apparmor/open
|
||||
tests/regression/apparmor/openat
|
||||
tests/regression/apparmor/pipe
|
||||
tests/regression/apparmor/pivot_root
|
||||
tests/regression/apparmor/posix_mq_rcv
|
||||
tests/regression/apparmor/posix_mq_snd
|
||||
tests/regression/apparmor/ptrace
|
||||
tests/regression/apparmor/ptrace_helper
|
||||
tests/regression/apparmor/pwrite
|
||||
tests/regression/apparmor/query_label
|
||||
tests/regression/apparmor/readdir
|
||||
tests/regression/apparmor/rename
|
||||
tests/regression/apparmor/rw
|
||||
tests/regression/apparmor/socketpair
|
||||
tests/regression/apparmor/swap
|
||||
tests/regression/apparmor/symlink
|
||||
tests/regression/apparmor/syscall_chroot
|
||||
tests/regression/apparmor/syscall_ioperm
|
||||
tests/regression/apparmor/syscall_iopl
|
||||
tests/regression/apparmor/syscall_mknod
|
||||
tests/regression/apparmor/syscall_mlockall
|
||||
tests/regression/apparmor/syscall_ptrace
|
||||
@@ -298,20 +252,11 @@ tests/regression/apparmor/syscall_setpriority
|
||||
tests/regression/apparmor/syscall_setscheduler
|
||||
tests/regression/apparmor/syscall_sysctl
|
||||
tests/regression/apparmor/sysctl_proc
|
||||
tests/regression/apparmor/sysv_mq_rcv
|
||||
tests/regression/apparmor/sysv_mq_snd
|
||||
tests/regression/apparmor/tcp
|
||||
tests/regression/apparmor/transition
|
||||
tests/regression/apparmor/unix_fd_client
|
||||
tests/regression/apparmor/unix_fd_server
|
||||
tests/regression/apparmor/unix_socket
|
||||
tests/regression/apparmor/unix_socket_client
|
||||
tests/regression/apparmor/unlink
|
||||
tests/regression/apparmor/userns
|
||||
tests/regression/apparmor/userns_setns
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
tests/regression/apparmor/xattrs_profile
|
||||
tests/regression/apparmor/coredump
|
||||
**/__pycache__/
|
||||
*.orig
|
||||
|
166
.gitlab-ci.yml
166
.gitlab-ci.yml
@@ -1,166 +0,0 @@
|
||||
---
|
||||
image: ubuntu:latest
|
||||
|
||||
# XXX - add a deploy stage to publish man pages, docs, and coverage
|
||||
# reports
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
.ubuntu-before_script:
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- apt-get update -qq
|
||||
- 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-before_script
|
||||
artifacts:
|
||||
name: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||
expire_in: 30 days
|
||||
untracked: true
|
||||
paths:
|
||||
- libraries/libapparmor/
|
||||
- parser/
|
||||
- binutils/
|
||||
- utils/
|
||||
- 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-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C libraries/libapparmor check
|
||||
|
||||
test-parser:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C parser check
|
||||
|
||||
test-binutils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C binutils check
|
||||
|
||||
test-utils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter pyflakes3 python3-coverage python3-notify2 python3-psutil python3-setuptools
|
||||
# See apparmor/apparmor#221
|
||||
- make -C parser/tst gen_dbus
|
||||
- make -C parser/tst gen_xtrans
|
||||
- make -C utils check
|
||||
- make -C utils/test coverage-regression
|
||||
artifacts:
|
||||
paths:
|
||||
- utils/test/htmlcov/
|
||||
when: always
|
||||
|
||||
test-mod-apparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C changehat/mod_apparmor check
|
||||
|
||||
test-profiles:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-extras
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
needs: []
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
> shellcheck.xml'
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: shellcheck.xml
|
||||
|
||||
# Disabled due to aa-logprof dependency on /sbin/apparmor_parser existing
|
||||
# - make -C profiles check-profiles
|
||||
|
||||
# test-pam_apparmor:
|
||||
# - stage: test
|
||||
# - script:
|
||||
# - cd changehat/pam_apparmor && make check
|
||||
|
||||
include:
|
||||
- template: SAST.gitlab-ci.yml
|
||||
- template: Secret-Detection.gitlab-ci.yml
|
||||
|
||||
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-before_script
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
script:
|
||||
- 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"
|
@@ -1,10 +0,0 @@
|
||||
# Don't follow source'd scripts
|
||||
disable=SC1090
|
||||
disable=SC1091
|
||||
|
||||
# dash supports 'local'
|
||||
disable=SC2039
|
||||
disable=SC3043
|
||||
|
||||
# dash supports 'echo -n'
|
||||
disable=SC3037
|
18
Makefile
18
Makefile
@@ -19,7 +19,7 @@ DIRS=libraries/libapparmor \
|
||||
|
||||
# with conversion to git, we don't export from the remote
|
||||
REPO_URL?=git@gitlab.com:apparmor/apparmor.git
|
||||
REPO_BRANCH?=master
|
||||
REPO_BRANCH?=apparmor-2.11
|
||||
|
||||
COVERITY_DIR=cov-int
|
||||
RELEASE_DIR=apparmor-${VERSION}
|
||||
@@ -39,8 +39,8 @@ TAR_EXCLUSIONS=
|
||||
.PHONY: tarball
|
||||
tarball: clean
|
||||
REPO_VERSION=`$(value REPO_VERSION_CMD)` && \
|
||||
$(MAKE) export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} && \
|
||||
$(MAKE) setup __SETUP_DIR=${RELEASE_DIR} && \
|
||||
make export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} && \
|
||||
make setup __SETUP_DIR=${RELEASE_DIR} && \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${RELEASE_DIR}.tar.gz ${RELEASE_DIR}
|
||||
|
||||
.PHONY: snapshot
|
||||
@@ -54,12 +54,12 @@ snapshot: clean
|
||||
.PHONY: coverity
|
||||
coverity: snapshot
|
||||
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
|
||||
$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
cov-build --dir $(COVERITY_DIR) -- make -C $(SNAPSHOT_NAME)/$(dir); \
|
||||
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-$(subst /,.,$(dir)).txt ;)
|
||||
$(foreach dir, libraries/libapparmor utils, \
|
||||
cov-build --dir $(COVERITY_DIR) --no-command --fs-capture-search $(SNAPSHOT_NAME)/$(dir); \
|
||||
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-python-$(subst /,.,$(dir)).txt ;)
|
||||
cov-build --dir $(COVERITY_DIR) -- sh -c \
|
||||
"$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
$(MAKE) -C $(SNAPSHOT_NAME)/$(dir);) "
|
||||
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
|
||||
|
||||
.PHONY: export_dir
|
||||
@@ -72,18 +72,18 @@ export_dir:
|
||||
clean:
|
||||
-rm -rf ${RELEASE_DIR} ./apparmor-${VERSION}~* ${COVERITY_DIR}
|
||||
for dir in $(DIRS); do \
|
||||
$(MAKE) -C $$dir clean; \
|
||||
make -C $$dir clean; \
|
||||
done
|
||||
|
||||
.PHONY: setup
|
||||
setup:
|
||||
cd $(__SETUP_DIR)/libraries/libapparmor && ./autogen.sh
|
||||
# parser has an extra doc to build
|
||||
$(MAKE) -C $(__SETUP_DIR)/parser extra_docs
|
||||
make -C $(__SETUP_DIR)/parser extra_docs
|
||||
# libraries/libapparmor needs configure to have run before
|
||||
# building docs
|
||||
$(foreach dir, $(filter-out libraries/libapparmor tests, $(DIRS)), \
|
||||
$(MAKE) -C $(__SETUP_DIR)/$(dir) docs;)
|
||||
make -C $(__SETUP_DIR)/$(dir) docs;)
|
||||
|
||||
.PHONY: tag
|
||||
tag:
|
||||
|
69
README.md
69
README.md
@@ -35,33 +35,16 @@ and questions to the
|
||||
[AppArmor mailing list](https://lists.ubuntu.com/mailman/listinfo/apparmor).
|
||||
|
||||
Bug reports can be filed against the AppArmor project on
|
||||
[GitLab](https://gitlab.com/apparmor/apparmor/-/issues) or reported to the mailing
|
||||
[launchpad](https://bugs.launchpad.net/apparmor) or reported to the mailing
|
||||
list directly for those who wish not to register for an account on
|
||||
GitLab. See the
|
||||
launchpad. See the
|
||||
[wiki page](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-bugs)
|
||||
for more information.
|
||||
|
||||
Security issues can be filed in GitLab by opening up a new [issue](https://gitlab.com/apparmor/apparmor/-/issues) and selecting the tick box ```This issue is confidential and should only be visible to team members with at least Reporter access.``` or directed to `security@apparmor.net`. Additional details can be found
|
||||
Security issues can be filed as security bugs on launchpad
|
||||
or directed to `security@apparmor.net`. Additional details can be found
|
||||
in the [wiki](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-security-vulnerabilities).
|
||||
|
||||
|
||||
--------------
|
||||
Privacy Policy
|
||||
--------------
|
||||
|
||||
The AppArmor security project respects users privacy and data and does not collect data from or on its users beyond what is required for a given component to function.
|
||||
|
||||
The AppArmor kernel security module will log violations to the audit subsystem, and those will be logged/forwarded/recorded on the user's system(s) according to how the administrator has logging configured. Again this is not forwarded to or collected by the AppArmor project.
|
||||
|
||||
The AppArmor userspace tools do not collect information on the system user beyond the logs and information needed to interact with the user. This is not forwarded to, nor collected by the AppArmor project.
|
||||
|
||||
Users may submit information as part of an email, bug report or merge request, etc. and that will be recorded as part of the mailing list, bug/issue tracker, or code repository but only as part of a user initiated action.
|
||||
|
||||
The AppArmor project does not collect information from contributors beyond their interactions with the AppArmor project, code, and community. However contributors are subject to the terms and conditions and privacy policy of the individual platforms (currently GitLab) should they choose to contribute through those platforms. And those platforms may collect data on the user that the AppArmor project does not.
|
||||
|
||||
Currently GitLab requires a user account to submit patches or report bugs and issues. If a contributor does not wish to create an account for these platforms the mailing list is available. Membership in the list is not required. Content from non-list members will be sent to moderation, to ensure that it is on topic, so there may be a delay in choosing to interact in this way.
|
||||
|
||||
|
||||
-------------
|
||||
Source Layout
|
||||
-------------
|
||||
@@ -111,7 +94,7 @@ $ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
### libapparmor:
|
||||
libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
@@ -126,7 +109,7 @@ $ make install
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
### Binary Utilities:
|
||||
Binary Utilities:
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
@@ -135,7 +118,7 @@ $ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Parser:
|
||||
parser:
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
@@ -145,16 +128,16 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Utilities:
|
||||
Utilities:
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check PYFLAKES=/usr/bin/pyflakes3
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Apache mod_apparmor:
|
||||
Apache mod_apparmor:
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
@@ -163,7 +146,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### PAM AppArmor:
|
||||
PAM AppArmor:
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
@@ -172,7 +155,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Profiles:
|
||||
Profiles:
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
@@ -181,9 +164,6 @@ $ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
Note that the empty local/* profile sniplets no longer get created by default.
|
||||
If you want them, run `make local` before running `make check`.
|
||||
|
||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||
some of the locale languages, you can override the default by passing
|
||||
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
||||
@@ -204,20 +184,6 @@ tests/regression/apparmor/README.
|
||||
|
||||
To run:
|
||||
|
||||
### Regression tests - using apparmor userspace installed on host
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make USE_SYSTEM=1
|
||||
$ sudo make tests USE_SYSTEM=1
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
|
||||
### Regression tests - using apparmor userspace from the tree.
|
||||
- [build libapparmor](#libapparmor)
|
||||
- [build binutils](#binary-utilities)
|
||||
- [build apparmor parser](#parser)
|
||||
- [build Pam apparmor](#pam-apparmor)
|
||||
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make
|
||||
@@ -348,15 +314,10 @@ The AppArmor userspace utilities are written with some assumptions about
|
||||
installed and available versions of other tools. This is a (possibly
|
||||
incomplete) list of known version dependencies:
|
||||
|
||||
The Python utilities require a minimum of Python 3.3.
|
||||
The Python utilities require a minimum of Python 2.7 (deprecated) or Python 3.3.
|
||||
Python 3.x is recommended. Python 2.x support is deprecated since AppArmor 2.11.
|
||||
|
||||
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
|
||||
|
||||
Perl is no longer needed since none of the utilities shipped to end users depend
|
||||
on it anymore.
|
||||
Some utilities (aa-exec, aa-notify and aa-decode) require Perl 5.10.1 or newer.
|
||||
|
||||
Most shell scripts are written for POSIX-compatible sh. aa-decode expects
|
||||
bash, probably version 3.2 and higher.
|
||||
|
@@ -19,11 +19,11 @@ include $(COMMONDIR)/Make.rules
|
||||
|
||||
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-status.8
|
||||
MANPAGES=aa-enabled.1 aa-exec.1
|
||||
|
||||
WARNINGS = -Wall
|
||||
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
|
||||
CPP_WARNINGS =
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -g -O2 -pipe
|
||||
@@ -36,7 +36,7 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS} $(EXTRA_WARNINGS)
|
||||
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
||||
#INCLUDEDIR = /usr/src/linux/include
|
||||
INCLUDEDIR =
|
||||
@@ -48,17 +48,12 @@ endif
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c aa_load.c
|
||||
SRCS = aa_enabled.c
|
||||
HDRS =
|
||||
BINTOOLS = aa-enabled aa-exec aa-features-abi
|
||||
SBINTOOLS = aa-status aa-load
|
||||
TOOLS = aa-enabled aa-exec
|
||||
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
ifdef WITH_LIBINTL
|
||||
AALIB += -lintl
|
||||
endif
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
# Using the system libapparmor so Makefile dependencies can't be used
|
||||
LIBAPPARMOR_A =
|
||||
@@ -98,7 +93,7 @@ po/%.pot: %.c
|
||||
|
||||
# targets arranged this way so that people who don't want full docs can
|
||||
# pick specific targets they want.
|
||||
arch: $(BINTOOLS) $(SBINTOOLS)
|
||||
arch: $(TOOLS)
|
||||
|
||||
manpages: $(MANPAGES)
|
||||
|
||||
@@ -111,7 +106,7 @@ all: arch indep
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(MAKE) clean $(BINTOOLS) $(SBINTOOLS) COVERAGE=1
|
||||
$(MAKE) clean $(TOOLS) COVERAGE=1
|
||||
|
||||
ifndef USE_SYSTEM
|
||||
$(LIBAPPARMOR_A):
|
||||
@@ -123,30 +118,18 @@ $(LIBAPPARMOR_A):
|
||||
fi
|
||||
endif
|
||||
|
||||
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-load: aa_load.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-exec: aa_exec.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-status: aa_status.c cJSON.o $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB) cJSON.o
|
||||
|
||||
cJSON.o: cJSON.c cJSON.h
|
||||
$(CC) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
.SILENT: check
|
||||
.PHONY: check
|
||||
check: check_pod_files tests
|
||||
|
||||
.SILENT: tests
|
||||
tests: $(BINTOOLS) $(SBINTOOLS) $(TESTS)
|
||||
tests: $(TOOLS) $(TESTS)
|
||||
echo "no tests atm"
|
||||
|
||||
.PHONY: install
|
||||
@@ -155,16 +138,12 @@ install: install-indep install-arch
|
||||
.PHONY: install-arch
|
||||
install-arch: arch
|
||||
install -m 755 -d ${BINDIR}
|
||||
install -m 755 ${BINTOOLS} ${BINDIR}
|
||||
install -m 755 -d ${SBINDIR}
|
||||
ln -sf aa-status ${SBINDIR}/apparmor_status
|
||||
install -m 755 ${SBINTOOLS} ${SBINDIR}
|
||||
install -m 755 ${TOOLS} ${BINDIR}
|
||||
|
||||
.PHONY: install-indep
|
||||
install-indep: indep
|
||||
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
ln -sf aa-status.8 ${DESTDIR}/${MANDIR}/man8/apparmor_status.8
|
||||
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
@@ -173,6 +152,6 @@ endif
|
||||
clean: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
|
||||
rm -f gmon.out
|
||||
rm -f $(BINTOOLS) $(SBINTOOLS) $(TESTS)
|
||||
rm -f $(TOOLS) $(TESTS)
|
||||
$(MAKE) -s -C po clean
|
||||
|
||||
|
@@ -48,11 +48,6 @@ Do not output anything to stdout. This option is intended to be used by
|
||||
scripts that simply want to use the exit code to determine if AppArmor is
|
||||
enabled.
|
||||
|
||||
=item -x, --exclusive
|
||||
|
||||
Require AppArmor to have exclusive access to shared LSM interfaces to
|
||||
be considered enabled.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
@@ -61,31 +56,27 @@ Upon exiting, B<aa-enabled> will set its exit status to the following values:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<0>
|
||||
=item 0:
|
||||
|
||||
if AppArmor is enabled.
|
||||
|
||||
=item B<1>
|
||||
=item 1:
|
||||
|
||||
if AppArmor is not enabled/loaded.
|
||||
|
||||
=item B<2>
|
||||
=item 2:
|
||||
|
||||
intentionally not used as an B<aa-enabled> exit status.
|
||||
|
||||
=item B<3>
|
||||
=item 3:
|
||||
|
||||
if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item B<4>
|
||||
=item 4:
|
||||
|
||||
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
|
||||
|
||||
=item B<10>
|
||||
|
||||
AppArmor is enabled but does not have access to shared LSM interfaces.
|
||||
|
||||
=item B<64>
|
||||
=item 64:
|
||||
|
||||
if any unexpected error or condition is encountered.
|
||||
|
||||
@@ -94,7 +85,7 @@ if any unexpected error or condition is encountered.
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -83,7 +83,7 @@ aa-exec.
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -1,97 +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-features-abi - Extract, validate and manipulate AppArmor feature abis
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-features-abi> [OPTIONS] <SOURCE> [OUTPUT OPTIONS]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-features-abi> is used to extract a features abi and output to
|
||||
either stdout or a specified file. A SOURCE_OPTION must be specified.
|
||||
If an output option is not specified the features abi is written to
|
||||
stdout.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-features-abi> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=item -d, --debug
|
||||
|
||||
show messages with debugging information
|
||||
|
||||
=item -v, --verbose
|
||||
|
||||
show messages with stats
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
=over 4
|
||||
|
||||
=item -x, --extract
|
||||
|
||||
Extract the features abi for the kernel
|
||||
|
||||
=item -f FILE, --file=FILE
|
||||
|
||||
Load the features abi from FILE and send it to OUTPUT OPTIONS.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OUTPUT OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --stdout
|
||||
|
||||
Write the features abi to I<stdout>, this is the default if no output option
|
||||
is specified.
|
||||
|
||||
=item -w FILE, --write FILE
|
||||
|
||||
Write the features abi to I<FILE>.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=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), aa_features(3), and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
@@ -20,7 +20,6 @@ void print_help(const char *command)
|
||||
{
|
||||
printf(_("%s: [options]\n"
|
||||
" options:\n"
|
||||
" -x | --exclusive Shared interfaces must be available\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"),
|
||||
command);
|
||||
@@ -31,6 +30,8 @@ void print_help(const char *command)
|
||||
/* Exit statuses and meanings are documented in the aa-enabled.pod file */
|
||||
static void exit_with_error(int saved_errno, int quiet)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch(saved_errno) {
|
||||
case ENOSYS:
|
||||
if (!quiet)
|
||||
@@ -49,11 +50,8 @@ static void exit_with_error(int saved_errno, int quiet)
|
||||
if (!quiet)
|
||||
printf(_("Maybe - insufficient permissions to determine availability.\n"));
|
||||
exit(4);
|
||||
case EBUSY:
|
||||
if (!quiet)
|
||||
printf(_("Partially - public shared interfaces are not available.\n"));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
printf(_("Error - %s\n"), strerror(saved_errno));
|
||||
exit(64);
|
||||
@@ -61,27 +59,22 @@ static void exit_with_error(int saved_errno, int quiet)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, enabled;
|
||||
int enabled;
|
||||
int quiet = 0;
|
||||
int require_shared = 0;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc > 3) {
|
||||
if (argc > 2) {
|
||||
printf(_("unknown or incompatible options\n"));
|
||||
print_help(argv[0]);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--quiet") == 0 ||
|
||||
strcmp(argv[i], "-q") == 0) {
|
||||
} else if (argc == 2) {
|
||||
if (strcmp(argv[1], "--quiet") == 0 ||
|
||||
strcmp(argv[1], "-q") == 0) {
|
||||
quiet = 1;
|
||||
} else if (strcmp(argv[i], "--exclusive") == 0 ||
|
||||
strcmp(argv[i], "-x") == 0) {
|
||||
require_shared = 1;
|
||||
} else if (strcmp(argv[i], "--help") == 0 ||
|
||||
strcmp(argv[i], "-h") == 0) {
|
||||
} else if (strcmp(argv[1], "--help") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else {
|
||||
printf(_("unknown option '%s'\n"), argv[1]);
|
||||
@@ -90,10 +83,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
enabled = aa_is_enabled();
|
||||
if (!enabled) {
|
||||
if (require_shared || errno != EBUSY)
|
||||
exit_with_error(errno, quiet);
|
||||
}
|
||||
if (!enabled)
|
||||
exit_with_error(errno, quiet);
|
||||
|
||||
if (!quiet)
|
||||
printf(_("Yes\n"));
|
||||
exit(0);
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
@@ -34,7 +33,6 @@ static const char *opt_namespace = NULL;
|
||||
static bool opt_debug = false;
|
||||
static bool opt_immediate = false;
|
||||
static bool opt_verbose = false;
|
||||
static pid_t pid = 0;
|
||||
|
||||
static void usage(const char *name, bool error)
|
||||
{
|
||||
@@ -62,7 +60,7 @@ static void usage(const char *name, bool error)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("[%ld] aa-exec: ERROR: " fmt "\n"), (long)pid, ## args)
|
||||
#define error(fmt, args...) _error(_("aa-exec: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -73,7 +71,7 @@ static void _error(const char *fmt, ...)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define debug(fmt, args...) _debug(_("[%ld] aa-exec: DEBUG: " fmt "\n"), (long)pid, ## args)
|
||||
#define debug(fmt, args...) _debug(_("aa-exec: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -86,7 +84,7 @@ static void _debug(const char *fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_("[%ld] " fmt "\n"), (long)pid, ## args)
|
||||
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -104,7 +102,7 @@ static void verbose_print_argv(char **argv)
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
fprintf(stderr, _("[%ld] exec"), (long)pid);
|
||||
fprintf(stderr, _("exec"));
|
||||
for (; *argv; argv++)
|
||||
fprintf(stderr, " %s", *argv);
|
||||
fprintf(stderr, "\n");
|
||||
@@ -131,13 +129,9 @@ static char **parse_args(int argc, char **argv)
|
||||
usage(argv[0], false);
|
||||
break;
|
||||
case 'p':
|
||||
if (opt_profile)
|
||||
error("Multiple -p/--profile parameters given");
|
||||
opt_profile = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
if (opt_namespace)
|
||||
error("Multiple -n/--namespace parameters given");
|
||||
opt_namespace = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
@@ -189,11 +183,6 @@ int main(int argc, char **argv)
|
||||
char name[PATH_MAX];
|
||||
int rc = 0;
|
||||
|
||||
/* IMPORTANT: pid must be initialized before doing anything else since
|
||||
* it is used in a global context when printing messages
|
||||
*/
|
||||
pid = getpid();
|
||||
|
||||
argv = parse_args(argc, argv);
|
||||
|
||||
if (opt_namespace || opt_profile)
|
||||
@@ -212,11 +201,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
if (errno == ENOENT) {
|
||||
error("%s '%s' does not exist",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EACCES) {
|
||||
error("insufficient permissions to change to the %s '%s'",
|
||||
if (errno == ENOENT || errno == EACCES) {
|
||||
error("%s '%s' does not exist\n",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EINVAL) {
|
||||
error("AppArmor interface not available");
|
||||
|
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include "../libraries/libapparmor/src/private.h"
|
||||
|
||||
static const char *progname = NULL;
|
||||
static const char *opt_file = NULL;
|
||||
static const char *opt_write = NULL;
|
||||
static bool opt_debug = false;
|
||||
static bool opt_verbose = false;
|
||||
static bool opt_extract = false;
|
||||
|
||||
static void usage(const char *name, bool error)
|
||||
{
|
||||
FILE *stream = stdout;
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
if (error) {
|
||||
stream = stderr;
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stream,
|
||||
_("USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
|
||||
"\n"
|
||||
"Output AppArmor feature abi from SOURCE to OUTPUT"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
#if 0
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
#endif
|
||||
" -h, --help display this help\n"
|
||||
"SOURCE:\n"
|
||||
" -f F, --file=F load features abi from file F\n"
|
||||
" -x, --extract extract features abi from the kernel\n"
|
||||
"OUTPUT OPTIONS:\n"
|
||||
" --stdout default, write features to stdout\n"
|
||||
" -w F, --write=F write features abi to the file F instead of stdout\n"
|
||||
"\n"), name);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("%s: ERROR: " fmt " - %m\n"), progname, ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define debug(fmt, args...) _debug(_("%s: DEBUG: " fmt "\n"), progname, ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_debug)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ARG_STDOUT 128
|
||||
|
||||
static char **parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
struct option long_opts[] = {
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"extract", no_argument, 0, 'x'},
|
||||
{"file", required_argument, 0, 'f'},
|
||||
{"write", required_argument, 0, 'w'},
|
||||
{"stdout", no_argument, 0, ARG_STDOUT},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], false);
|
||||
break;
|
||||
case 'x':
|
||||
opt_extract = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_file = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
opt_write = optarg;
|
||||
break;
|
||||
case ARG_STDOUT:
|
||||
opt_write = NULL;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return argv + optind;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: add features intersection and testing */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct aa_features *features;
|
||||
autoclose int in = -1;
|
||||
autoclose int out = -1;
|
||||
int rc = 0;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
argv = parse_args(argc, argv);
|
||||
|
||||
if (!opt_extract && !opt_file)
|
||||
usage(argv[0], true);
|
||||
if (opt_extract && opt_file) {
|
||||
error("options --extract and --file are mutually exclusive");
|
||||
}
|
||||
if (opt_extract) {
|
||||
rc = aa_features_new_from_kernel(&features);
|
||||
if (rc == -1)
|
||||
error("failed to extract features abi from the kernel");
|
||||
}
|
||||
if (opt_file) {
|
||||
in = open(opt_file, O_RDONLY);
|
||||
if (in == -1)
|
||||
error("failed to open file '%s'", opt_file);
|
||||
rc = aa_features_new_from_file(&features, in);
|
||||
if (rc == -1)
|
||||
error("failed to load features abi from file '%s'", opt_file);
|
||||
}
|
||||
|
||||
|
||||
if (opt_write) {
|
||||
out = open(opt_write, O_WRONLY | O_CREAT, 00600);
|
||||
if (out == -1)
|
||||
error("failed to open output file '%s'", opt_write);
|
||||
} else {
|
||||
out = fileno(stdout);
|
||||
if (out == -1)
|
||||
error("failed to get stdout");
|
||||
}
|
||||
rc = aa_features_write_to_fd(features, out);
|
||||
if (rc == -1)
|
||||
error("failed to write features abi");
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,408 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for asprintf() */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* TODO: implement config locations - value can change */
|
||||
#define DEFAULT_CONFIG_LOCATIONS "/etc/apparmor/parser.conf"
|
||||
#define DEFAULT_POLICY_LOCATIONS "/var/cache/apparmor:/etc/apparmor.d/cache.d:/etc/apparmor.d/cache"
|
||||
#define CACHE_FEATURES_FILE ".features"
|
||||
|
||||
bool opt_debug = false;
|
||||
bool opt_verbose = false;
|
||||
bool opt_dryrun = false;
|
||||
bool opt_force = false;
|
||||
bool opt_config = false;
|
||||
|
||||
#define warning(fmt, args...) _error(_("aa-load: WARN: " fmt "\n"), ## args)
|
||||
#define error(fmt, args...) _error(_("aa-load: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _debug(opt_verbose, _(fmt "\n"), ## args)
|
||||
#define debug(fmt, args...) _debug(opt_debug, _("aa-load: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(bool opt_displayit, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_displayit)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int have_enough_privilege(const char *command)
|
||||
{
|
||||
uid_t uid, euid;
|
||||
|
||||
uid = getuid();
|
||||
euid = geteuid();
|
||||
|
||||
if (uid != 0 && euid != 0) {
|
||||
error("%s: Sorry. You need root privileges to run this program.\n",
|
||||
command);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (uid != 0 && euid == 0) {
|
||||
error("%s: Aborting! You've set this program setuid root.\n"
|
||||
"Anybody who can run this program can update "
|
||||
"your AppArmor profiles.\n", command);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int load_config(const char *file)
|
||||
{
|
||||
/* TODO */
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* load a single policy cache file to the kernel
|
||||
*/
|
||||
static int load_policy_file(const char *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
struct aa_kernel_interface *kernel_interface;
|
||||
|
||||
if (aa_kernel_interface_new(&kernel_interface, NULL, NULL)) {
|
||||
rc = -errno;
|
||||
error("Failed to open kernel interface '%s': %m", file);
|
||||
return rc;
|
||||
}
|
||||
if (!opt_dryrun &&
|
||||
aa_kernel_interface_replace_policy_from_file(kernel_interface,
|
||||
AT_FDCWD, file)) {
|
||||
rc = -errno;
|
||||
error("Failed to load policy into kernel '%s': %m", file);
|
||||
}
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void validate_features(const char *dir_path)
|
||||
{
|
||||
aa_features *kernel_features;
|
||||
|
||||
if (aa_features_new_from_kernel(&kernel_features) == -1) {
|
||||
error("Failed to obtain features: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aa_features_check(AT_FDCWD, dir_path, kernel_features) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
/* features file does not exist
|
||||
* not an issue when loading cache policies from dir
|
||||
*/
|
||||
}
|
||||
else if (errno == EEXIST) {
|
||||
warning("Overlay features do not match kernel features");
|
||||
}
|
||||
}
|
||||
aa_features_unref(kernel_features);
|
||||
}
|
||||
|
||||
/**
|
||||
* load a directory of policy cache files to the kernel
|
||||
* This does not do a subdir search to find the kernel match but
|
||||
* tries to load the dir regardless of whether its features match
|
||||
*
|
||||
* The hierarchy looks like
|
||||
*
|
||||
* dir/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
|
||||
static int load_policy_dir(const char *dir_path)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
int rc = 0;
|
||||
char *file;
|
||||
size_t len;
|
||||
|
||||
validate_features(dir_path);
|
||||
|
||||
d = opendir(dir_path);
|
||||
if (!d) {
|
||||
rc = -errno;
|
||||
error("Failed to open directory '%s': %m", dir_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
/* Only check regular files for now */
|
||||
if (dir->d_type == DT_REG) {
|
||||
len = strnlen(dir->d_name, PATH_MAX);
|
||||
/* Ignores .features */
|
||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (asprintf(&file, "%s/%s", dir_path, dir->d_name) == -1) {
|
||||
error("Failure allocating memory");
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
load_policy_file(file);
|
||||
free(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load_hashed_policy - find policy hashed dir and load it
|
||||
*
|
||||
* load/replace all policy from a policy hierarchy directory
|
||||
*
|
||||
* Returns: 0 on success < -errno
|
||||
*
|
||||
* It will find the subdir that matches the kernel and load all
|
||||
* precompiled policy files from it.
|
||||
*
|
||||
* The hierarchy looks something like
|
||||
*
|
||||
* location/
|
||||
* kernel_hash1.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
* kernel_hash2.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
static int load_policy_by_hash(const char *location)
|
||||
{
|
||||
aa_policy_cache *policy_cache = NULL;
|
||||
int rc;
|
||||
|
||||
if ((rc = aa_policy_cache_new(&policy_cache, NULL, AT_FDCWD, location, 0))) {
|
||||
rc = -errno;
|
||||
error("Failed to open policy cache '%s': %m", location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (opt_debug) {
|
||||
/* show hash directory under location that matches the
|
||||
* current kernel
|
||||
*/
|
||||
char *cache_loc = aa_policy_cache_dir_path_preview(NULL, AT_FDCWD, location);
|
||||
if (!cache_loc) {
|
||||
rc = -errno;
|
||||
error("Failed to find cache location '%s': %m", location);
|
||||
goto out;
|
||||
}
|
||||
debug("Loading cache from '%s'\n", cache_loc);
|
||||
free(cache_loc);
|
||||
}
|
||||
|
||||
if (!opt_dryrun) {
|
||||
if ((rc = aa_policy_cache_replace_all(policy_cache, NULL)) < 0) {
|
||||
error("Failed to load policy cache '%s': %m", location);
|
||||
} else {
|
||||
verbose("Success - Loaded policy cache '%s'", location);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* load_arg - calls specific load functions for files and directories
|
||||
*
|
||||
* load/replace all policy files/dir in arg
|
||||
*
|
||||
* Returns: 0 on success, 1 on failure.
|
||||
*
|
||||
* It will load by hash subtree first, and fallback to a cache dir
|
||||
* If not a directory, it will try to load it as a cache file
|
||||
*/
|
||||
static int load_arg(char *arg)
|
||||
{
|
||||
char **location = NULL;
|
||||
int i, n, rc = 0;
|
||||
|
||||
|
||||
/* arg can specify an overlay of multiple cache locations */
|
||||
if ((n = aa_split_overlay_str(arg, &location, 0, true)) == -1) {
|
||||
error("Failed to parse overlay locations: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct stat st;
|
||||
debug("Trying to open %s", location[i]);
|
||||
if (stat(location[i], &st) == -1) {
|
||||
error("Failed stat of '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* try hash dir subtree first */
|
||||
if (load_policy_by_hash(location[i]) < 0) {
|
||||
error("Failed load policy by hash '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
/* fall back to cache dir */
|
||||
if (load_policy_dir(location[i]) < 0) {
|
||||
error("Failed load policy by directory '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
} else if (load_policy_file(location[i]) < 0) {
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
free(location[i]);
|
||||
free(location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void print_usage(const char *command)
|
||||
{
|
||||
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"
|
||||
" -v, --verbose display progress and error messages\n"
|
||||
" -n, --dry-run do everything except actual load\n"
|
||||
" -h, --help this message\n",
|
||||
command);
|
||||
}
|
||||
|
||||
static const char *short_options = "c:dfvnh";
|
||||
struct option long_options[] = {
|
||||
{"config", 1, 0, 'c'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"force", 0, 0, 'f'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"dry-run", 0, 0, 'n'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
static int process_args(int argc, char **argv)
|
||||
{
|
||||
int c, o;
|
||||
|
||||
opterr = 1;
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
|
||||
switch(c) {
|
||||
case 0:
|
||||
error("error in argument processing\n");
|
||||
exit(1);
|
||||
break;
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_force = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt_dryrun = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'c':
|
||||
/* TODO: reserved config location,
|
||||
* act as a bad arg for now, when added update usage
|
||||
*/
|
||||
//opt_config = true; uncomment when implemented
|
||||
/* Fall through */
|
||||
default:
|
||||
error("unknown argument: '%s'\n\n", optarg);
|
||||
print_usage(argv[1]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
if (!opt_dryrun && have_enough_privilege(argv[0]))
|
||||
return 1;
|
||||
|
||||
/* if no location use the default one */
|
||||
if (optind == argc) {
|
||||
if (!opt_config && load_config(DEFAULT_CONFIG_LOCATIONS) == 0) {
|
||||
verbose("Loaded policy config");
|
||||
}
|
||||
if ((rc = load_arg(DEFAULT_POLICY_LOCATIONS)))
|
||||
verbose("Loading policy from default location '%s'", DEFAULT_POLICY_LOCATIONS);
|
||||
else
|
||||
debug("No policy specified, and no policy config or policy in default locations");
|
||||
}
|
||||
for (i = optind; i < argc; i++) {
|
||||
/* Try to load all policy locations even if one fails
|
||||
* but always return an error if any fail
|
||||
*/
|
||||
|
||||
int tmp = load_arg(argv[i]);
|
||||
if (!rc)
|
||||
rc = tmp;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
1095
binutils/aa_status.c
1095
binutils/aa_status.c
File diff suppressed because it is too large
Load Diff
3074
binutils/cJSON.c
3074
binutils/cJSON.c
File diff suppressed because it is too large
Load Diff
293
binutils/cJSON.h
293
binutils/cJSON.h
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 13
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable adress area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,73 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_enabled.c:21
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -x | --exclusive Shared interfaces must be available\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:37
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:41
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:50
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:54
|
||||
#, c-format
|
||||
msgid "Partially - public shared interfaces are not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:58
|
||||
#, c-format
|
||||
msgid "Error - %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:73
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:87
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:98
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
@@ -1,55 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_exec.c:50
|
||||
#, c-format
|
||||
msgid ""
|
||||
"USAGE: %s [OPTIONS] <prog> <args>\n"
|
||||
"\n"
|
||||
"Confine <prog> with the specified PROFILE.\n"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
" -p PROFILE, --profile=PROFILE\t\tPROFILE to confine <prog> with\n"
|
||||
" -n NAMESPACE, --namespace=NAMESPACE\tNAMESPACE to confine <prog> in\n"
|
||||
" -d, --debug\t\t\t\tshow messages with debugging information\n"
|
||||
" -i, --immediate\t\t\tchange profile immediately instead of at exec\n"
|
||||
" -v, --verbose\t\t\t\tshow messages with stats\n"
|
||||
" -h, --help\t\t\t\tdisplay this help\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:65
|
||||
#, c-format
|
||||
msgid "[%ld] aa-exec: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:76
|
||||
#, c-format
|
||||
msgid "[%ld] aa-exec: DEBUG: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:89
|
||||
#, c-format
|
||||
msgid "[%ld] "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:107
|
||||
#, c-format
|
||||
msgid "[%ld] exec"
|
||||
msgstr ""
|
@@ -1,51 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 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"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_features_abi.c:53
|
||||
#, c-format
|
||||
msgid ""
|
||||
"USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
|
||||
"\n"
|
||||
"Output AppArmor feature abi from SOURCE to OUTPUT\n"
|
||||
"OPTIONS:\n"
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
" -h, --help display this help\n"
|
||||
"SOURCE:\n"
|
||||
" -f F, --file=F load features abi from file F\n"
|
||||
" -x, --extract extract features abi from the kernel\n"
|
||||
"OUTPUT OPTIONS:\n"
|
||||
" --stdout default, write features to stdout\n"
|
||||
" -w F, --write=F write features abi to the file F instead of stdout\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:73
|
||||
#, c-format
|
||||
msgid "%s: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:85
|
||||
#, c-format
|
||||
msgid "%s: DEBUG: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:98
|
||||
msgid "\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Afrikaans translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-03-04 17:55+0000\n"
|
||||
"Last-Translator: bernard stafford <Unknown>\n"
|
||||
"Language-Team: Afrikaans <af@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-03-05 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build e0878392dc799b267dea80578fa65500a5d74155)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opsies]\n"
|
||||
" opsies:\n"
|
||||
" -q | --quiet Moenie druk uit enige boodskappe\n"
|
||||
" -h | --help Afdruk hulp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "onbekende of onversoenbare opsies\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "onbekende opsie '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Geen - nie beskikbaar op hierdie stelsel.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nee - gestremde by stewel.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Miskien - beleid koppelvlak nie beskikbaar.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Miskien - onvoldoende toestemmings om beskikbaarheid te bepaal.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fout - '%s'\n"
|
@@ -8,14 +8,14 @@ msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-02-09 23:55+0000\n"
|
||||
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
|
||||
"PO-Revision-Date: 2016-03-20 01:58+0000\n"
|
||||
"Last-Translator: Tobias Bannert <Unknown>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-03-21 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 17947)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
@@ -26,20 +26,16 @@ msgid ""
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [Optionen]\n"
|
||||
" Optionen:\n"
|
||||
" -q | --quiet Keine Nachrichten anzeigen\n"
|
||||
" -h | --help Hilfetext anzeigen\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "unbekannte oder nicht kompatible Optionen\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "unbekannte Option »%s«\n"
|
||||
msgstr "Unbekannte Option »%s«\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
@@ -59,15 +55,14 @@ msgstr "Nein – beim Start deaktiviert.\n"
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Vielleicht – Richtlinienschnittstelle nicht verfügbar.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Vielleicht – ungenügende Berechtigungen, um die Verfügbarkeit zu prüfen\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fehler – »%s«\n"
|
||||
msgstr "Fehler - »%s«\n"
|
||||
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-19 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17925)\n"
|
||||
"Language: en_GB\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,71 +0,0 @@
|
||||
# Spanish translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-06-09 14:01+0000\n"
|
||||
"Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-06-10 04:32+0000\n"
|
||||
"X-Generator: Launchpad (build 18978)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opciones]\n"
|
||||
" opciones:\n"
|
||||
" -q | --quiet No emitir ningún mensaje\n"
|
||||
" -h | --help Mostrar la ayuda\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opciones desconocidas o incompatibles\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "se desconoce la opción «%s»\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sí\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No; no disponible en este sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No; desactivado durante el arranque.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Quizá; interfaz de directiva no disponible.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Quizá; permisos insuficientes para determinar disponibilidad.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Error: «%s»\n"
|
@@ -1,67 +0,0 @@
|
||||
# Persian translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-12-27 08:16+0000\n"
|
||||
"Last-Translator: VahidNameni <Unknown>\n"
|
||||
"Language-Team: Persian <fa@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-12-28 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build bceb5ef013b87ef7aafe0755545ceb689ca7ac60)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "تنظیم نامعلوم یا ناسازگار\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "تنظیم '%s' ناشناخته است\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "بله\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "خیر- در این سیستم موجود نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "خیر - غیرفعال در زمان boot.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "شاید - رابط سیاست گذاری در دسترس نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "شاید - دسترسی ناکافی جهت شناسایی در دسترس پذیری.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "خطا - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Finnish translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-01-29 07:44+0000\n"
|
||||
"Last-Translator: Jiri Grönroos <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-01-30 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build b8d1327fd820d6bf500589d6da587d5037c7d88e)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "tuntemattomat tai yhteensopimattomat valinnat\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "tuntematon valinta '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Kyllä\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ei - ei käytettävissä tässä järjestelmässä.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ei - poistettu käytöstä käynnistyksen yhteydessä.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Virhe - '%s'\n"
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-03-04 04:35+0000\n"
|
||||
"X-Generator: Launchpad (build 17936)\n"
|
||||
"Language: pt\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,72 +0,0 @@
|
||||
# Romanian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-02-20 21:47+0000\n"
|
||||
"Last-Translator: Daniel Slavu <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-02-21 05:39+0000\n"
|
||||
"X-Generator: Launchpad (build 19413b719a8df7423ab1390528edadce9e0e4aca)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opțiuni]\n"
|
||||
" opțiuni:\n"
|
||||
" -q | --calm Nu imprima niciun mesaj\n"
|
||||
" -h | - ajutor Imprimare ajutor\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opțiuni necunoscute sau incompatibile\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opțiune necunoscută '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Da\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nu - nu este disponibil pe acest sistem.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nu - dezactivat la pornire.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Poate - interfața politică nu este disponibilă.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Poate - permisiuni insuficiente pentru a determina disponibilitatea.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Eroare - '%s'\n"
|
@@ -9,13 +9,13 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2016-03-29 14:46+0000\n"
|
||||
"Last-Translator: Eugene Roskin <Unknown>\n"
|
||||
"Last-Translator: Eugene Marshal <Unknown>\n"
|
||||
"Language-Team: Russian <ru@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-03-30 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 17967)\n"
|
||||
"Language: ru\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,72 +0,0 @@
|
||||
# Swedish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-09-08 03:51+0000\n"
|
||||
"Last-Translator: Jonatan Nyberg <Unknown>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" flaggor:\n"
|
||||
" -q | --quiet Skriv inte ut några meddelanden\n"
|
||||
" -h | --help Skriv ut hjälp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "okända eller inkompatibla flaggor\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "okänd flagga '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nej - inte tillgänglig på detta system.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nej - inaktiverad vid uppstart.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Kanske - policy gränssnitt inte tillgängliga.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Kanske - otillräckliga behörigheter för att bestämma tillgängligheten.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fel - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Swahili translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-11-14 12:33+0000\n"
|
||||
"Last-Translator: Swahilinux Administration <admin@swahilinux.org>\n"
|
||||
"Language-Team: Swahili <sw@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-11-15 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build c597c3229eb023b1e626162d5947141bf7befb13)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [chaguzi]\n"
|
||||
" chaguzi:\n"
|
||||
" -q | --quiet Usichapishe jumbe yoyote\n"
|
||||
" -h | --help Chapisha msaada\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "chaguo lisilojulikana au lisilofaa\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "chaguo lisilojulikana '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ndio\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "La - haipo kwenye mfumo huu.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "La - ilizimwa kwenye washi.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Labda - kiolesura cha faragha hakipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Labda - hamna ruhusa ya kutosha ili kuamua kama ipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Dosari - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Turkish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-05-19 23:10+0000\n"
|
||||
"Last-Translator: Kudret EMRE <kudretemre@hotmail.com>\n"
|
||||
"Language-Team: Turkish <tr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [seçenekler]\n"
|
||||
" seçenekler:\n"
|
||||
" -q | --quiet Hiçbir mesajı gösterme\n"
|
||||
" -h | --help Yardımı görüntüler\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "bilinmeyen veya uyumsuz seçenekler\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "bilinmeyen seçenek '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Evet\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Hayır - Bu sistemde kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Hayır - önyüklemede devredışı bırakıldı.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Belki - policy arayüzü kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Belki - kullanılabilir olup olmadığını denetlemek için yetersiz yetki.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Hata - '%s'\n"
|
@@ -70,8 +70,6 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
|
||||
LDLIBS = -lapparmor
|
||||
endif
|
||||
|
||||
APXS_CFLAGS="-Wc,$(EXTRA_WARNINGS)"
|
||||
|
||||
.PHONY: libapparmor_check
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check: ; $(ERROR_MESSAGE)
|
||||
@@ -82,14 +80,14 @@ all: libapparmor_check $(TARGET) docs
|
||||
docs: ${MANPAGES} ${HTMLMANPAGES}
|
||||
|
||||
%.so: %.c
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} ${APXS_CFLAGS} -c $< ${LDLIBS}
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} -c $< ${LDLIBS}
|
||||
mv .libs/$@ .
|
||||
|
||||
.PHONY: install
|
||||
install: ${TARGET} ${MANPAGES}
|
||||
mkdir -p ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
install -m 755 $< ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
make install_manpages DESTDIR=${DESTDIR}
|
||||
|
||||
.PHONY: clean
|
||||
clean: pod_clean
|
||||
|
@@ -30,10 +30,6 @@
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
/* should the following be configurable? */
|
||||
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
|
||||
#define DEFAULT_URI_HAT "DEFAULT_URI"
|
||||
@@ -69,7 +65,7 @@ typedef struct {
|
||||
* memory will be wiped out, and the magic_token will be lost, so apache
|
||||
* wouldn't be able to change_hat back out. */
|
||||
static int
|
||||
aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unused_ server_rec *s)
|
||||
aa_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
||||
{
|
||||
apr_file_t *file;
|
||||
apr_size_t size = sizeof(magic_token);
|
||||
@@ -93,7 +89,7 @@ aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unus
|
||||
* to protect ourselves from bugs in parsing network input, but before
|
||||
* we change_hat to the uri specific hat. */
|
||||
static void
|
||||
aa_child_init(unused_ apr_pool_t *p, unused_ server_rec *s)
|
||||
aa_child_init(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -264,7 +260,7 @@ aa_exit_hat(request_rec *r)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_path(unused_ cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -291,7 +287,7 @@ immunix_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -351,7 +347,7 @@ aa_merge_dir_config(apr_pool_t *p, void *parent, void *child)
|
||||
*/
|
||||
|
||||
static void *
|
||||
aa_create_srv_config(apr_pool_t *p, unused_ server_rec *srv)
|
||||
aa_create_srv_config(apr_pool_t *p, server_rec *srv)
|
||||
{
|
||||
apparmor_srv_cfg *newcfg = (apparmor_srv_cfg *) apr_pcalloc(p, sizeof(*newcfg));
|
||||
|
||||
@@ -401,7 +397,7 @@ static const command_rec mod_apparmor_cmds[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
register_hooks(unused_ apr_pool_t *p)
|
||||
register_hooks(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(aa_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_child_init(aa_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
@@ -412,7 +408,7 @@ register_hooks(unused_ apr_pool_t *p)
|
||||
|
||||
module AP_MODULE_DECLARE_DATA apparmor_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
aa_create_dir_config, /* dir config creator */
|
||||
aa_create_dir_config, /* dir config creater */
|
||||
NULL, /* dir merger --- default is to override */
|
||||
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
|
||||
aa_create_srv_config, /* server config */
|
||||
|
@@ -135,11 +135,11 @@ may not work correctly. For Apache 2.4 users, you should enable the mpm_prefork
|
||||
module.
|
||||
|
||||
There are likely other bugs lurking about; if you find any, please report
|
||||
them at L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
them at L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor_parser(8), aa_change_hat(2) and
|
||||
apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -54,7 +54,7 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
|
||||
AA_LINK_FLAGS = -L$(LIBAPPARMOR_PATH)
|
||||
AA_LDLIBS = -lapparmor
|
||||
endif
|
||||
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(EXTRA_WARNINGS) $(LIBAPPARMOR_INCLUDE)
|
||||
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
|
||||
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS) $(LDFLAGS)
|
||||
LIBS=-lpam $(AA_LDLIBS)
|
||||
OBJECTS=${NAME}.o get_options.o
|
||||
@@ -82,7 +82,7 @@ SECDIR ?= ${DESTDIR}/lib/security
|
||||
.PHONY: install
|
||||
install: $(NAME).so
|
||||
install -m 755 -d $(SECDIR)
|
||||
install -m 755 $(NAME).so $(SECDIR)/
|
||||
install -m 555 $(NAME).so $(SECDIR)/
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
@@ -67,10 +67,10 @@ to syslog.
|
||||
References
|
||||
----------
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
http://developer.novell.com/wiki/index.php/Novell_AppArmor
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
||||
See also: change_hat(3), and the Linux-PAM online documentation at
|
||||
|
@@ -45,10 +45,6 @@
|
||||
|
||||
int debug_flag = 0;
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
static struct config default_config = {
|
||||
.hat_type[0] = eGroupname,
|
||||
.hat_type[1] = eDefault,
|
||||
@@ -58,14 +54,14 @@ static struct config default_config = {
|
||||
/* --- session management functions (only) --- */
|
||||
|
||||
PAM_EXTERN int
|
||||
pam_sm_close_session (unused_ pam_handle_t *pamh, unused_ int flags,
|
||||
unused_ int argc, unused_ const char **argv)
|
||||
pam_sm_close_session (pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_open_session(pam_handle_t *pamh, unused_ int flags,
|
||||
int pam_sm_open_session(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int fd, retval, pam_retval = PAM_SUCCESS;
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
@@ -42,13 +42,12 @@ endif
|
||||
|
||||
define nl
|
||||
|
||||
|
||||
endef
|
||||
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
|
||||
|
||||
ifndef PYTHON_VERSIONS
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python3)
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python2 python3)
|
||||
endif
|
||||
|
||||
ifndef PYTHON
|
||||
@@ -58,18 +57,6 @@ endif
|
||||
#Helper function to be used with $(call pyalldo, run_test_with_all.py)
|
||||
pyalldo=set -e; $(foreach py, $(PYTHON_VERSIONS), $(py) $(1);)
|
||||
|
||||
# Common set of compiler warnings
|
||||
_EXTRA_WARNINGS = -Wall -Wsign-compare -Wmissing-field-initializers -Wformat -Wformat-security -Wunused-parameter -Wimplicit-fallthrough
|
||||
EXTRA_WARNINGS := $(shell for warning in ${_EXTRA_WARNINGS} ; do \
|
||||
if ${CC} $${warning} -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then \
|
||||
echo "$${warning}"; \
|
||||
else \
|
||||
echo "***" >&2 ; \
|
||||
echo "WARNING: unable to use $${warning} with ${CC}, dropping" >&2 ; \
|
||||
echo "***" >&2 ; \
|
||||
fi ; \
|
||||
done)
|
||||
|
||||
.PHONY: version
|
||||
.SILENT: version
|
||||
version:
|
||||
@@ -87,6 +74,40 @@ endif
|
||||
pod_clean:
|
||||
-rm -f ${MANPAGES} *.[0-9].gz ${HTMLMANPAGES} pod2htm*.tmp
|
||||
|
||||
# =====================
|
||||
# generate list of capabilities based on
|
||||
# /usr/include/linux/capabilities.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# emits defined capabilities in a simple list, e.g. "CAP_NAME CAP_NAME2"
|
||||
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | LC_ALL=C sort)
|
||||
|
||||
.PHONY: list_capabilities
|
||||
list_capabilities: /usr/include/linux/capability.h
|
||||
@echo "$(CAPABILITIES)"
|
||||
|
||||
# =====================
|
||||
# generate list of network protocols based on
|
||||
# sys/socket.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# These are the families that it doesn't make sense for apparmor
|
||||
# to mediate. We use PF_ here since that is what is required in
|
||||
# bits/socket.h, but we will rewrite these as AF_.
|
||||
|
||||
FILTER_FAMILIES=PF_UNIX
|
||||
|
||||
__FILTER=$(shell echo $(strip $(FILTER_FAMILIES)) | sed -e 's/ /\\\|/g')
|
||||
|
||||
# emits the AF names in a "AF_NAME NUMBER," pattern
|
||||
AF_NAMES=$(shell echo "\#include <sys/socket.h>" | cpp -dM | LC_ALL=C sed -n -e '/$(__FILTER)/d' -e 's/PF_LOCAL/PF_UNIX/' -e 's/^\#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$$/AF_\1 \2,/p' | sort -n -k2)
|
||||
|
||||
.PHONY: list_af_names
|
||||
list_af_names:
|
||||
@echo "$(AF_NAMES)"
|
||||
|
||||
# =====================
|
||||
# manpages
|
||||
# =====================
|
||||
|
@@ -1 +1 @@
|
||||
4.0.0~beta2
|
||||
2.11.2
|
||||
|
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# =====================
|
||||
# generate list of network protocols based on
|
||||
# sys/socket.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# It doesn't make sense for AppArmor to mediate PF_UNIX, filter it out. Search
|
||||
# for "PF_" constants since that is what is required in bits/socket.h, but
|
||||
# rewrite as "AF_".
|
||||
|
||||
echo "#include <sys/socket.h>" | \
|
||||
cpp -dM | \
|
||||
LC_ALL=C sed -n \
|
||||
-e '/PF_UNIX/d' \
|
||||
-e 's/PF_LOCAL/PF_UNIX/' \
|
||||
-e 's/^#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$/AF_\1 \2,/p' | \
|
||||
sort -n -k2
|
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# =====================
|
||||
# generate list of capabilities based on
|
||||
# /usr/include/linux/capabilities.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
echo "#include <linux/capability.h>" | \
|
||||
cpp -dM | \
|
||||
LC_ALL=C sed -n \
|
||||
-e '/CAP_EMPTY_SET/d' \
|
||||
-e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$/CAP_\1/p' | \
|
||||
LC_ALL=C sort
|
137
deprecated/rc.aaeventd.redhat
Normal file
137
deprecated/rc.aaeventd.redhat
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/aaeventd
|
||||
# and its symbolic link
|
||||
# /sbin/rcaaeventd
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor Notification and Reporting daemon
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: aaeventd
|
||||
# Required-Start: apparmor
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop:
|
||||
# Short-Description: AppArmor Notification and Reporting
|
||||
# Description: AppArmor Notification and Reporting daemon
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# source function library
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ]; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
elif [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sd_log_success_msg() {
|
||||
echo -n "$*"
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_warning_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_skipped_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_failure_msg() {
|
||||
echo -n "$*"
|
||||
failure
|
||||
echo
|
||||
}
|
||||
|
||||
sd_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
action "${STRING} " "$@"
|
||||
return $?
|
||||
}
|
||||
|
||||
start_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" daemon --pidfile $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
|
||||
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" daemon --pidfile $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
|
||||
fi
|
||||
}
|
||||
|
||||
stop_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -p $AA_EV_PIDFILE -INT $AA_EV_BIN
|
||||
fi
|
||||
if [ -f "$SD_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -p $SD_EV_PIDFILE -INT $SD_EV_BIN
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
sd_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
stop_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload|try-restart)
|
||||
stop_aa_event
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for service AppArmor Event daemon:"
|
||||
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
|
||||
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
|
||||
rc_status -v
|
||||
else
|
||||
rc_status -u
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
133
deprecated/rc.aaeventd.suse
Normal file
133
deprecated/rc.aaeventd.suse
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003 2004, 2005, 2006, 2007
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/aaeventd
|
||||
# and its symbolic link
|
||||
# /sbin/rcaaeventd
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor Notification and Reporting daemon
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: aaeventd
|
||||
# Required-Start: apparmor
|
||||
# Required-Stop: $null
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop:
|
||||
# Short-Description: AppArmor Notification and Reporting
|
||||
# Description: AppArmor Notification and Reporting daemon
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# source function library
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ]; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
elif [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Ugh, SUSE doesn't implement action
|
||||
sd_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
"$@"
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ] ; then
|
||||
log_success_msg $"$STRING "
|
||||
else
|
||||
log_failure_msg $"$STRING "
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
sd_log_success_msg() {
|
||||
log_success_msg $*
|
||||
}
|
||||
|
||||
sd_log_warning_msg() {
|
||||
log_warning_msg $*
|
||||
}
|
||||
|
||||
sd_log_failure_msg() {
|
||||
log_failure_msg $*
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
|
||||
}
|
||||
|
||||
start_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" startproc -p $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
|
||||
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" startproc -p $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
|
||||
fi
|
||||
}
|
||||
|
||||
stop_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $AA_EV_PIDFILE -INT $AA_EV_BIN
|
||||
fi
|
||||
if [ -f "$SD_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $SD_EV_PIDFILE -INT $SD_EV_BIN
|
||||
fi
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
sd_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
stop_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload|try-restart)
|
||||
stop_aa_event
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for service AppArmor Event daemon:"
|
||||
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
|
||||
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
|
||||
rc_status -v
|
||||
else
|
||||
rc_status -u
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
||||
|
6860
deprecated/utils/Immunix/AppArmor.pm
Executable file
6860
deprecated/utils/Immunix/AppArmor.pm
Executable file
File diff suppressed because it is too large
Load Diff
124
deprecated/utils/Immunix/Config.pm
Normal file
124
deprecated/utils/Immunix/Config.pm
Normal file
@@ -0,0 +1,124 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2006 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
package Immunix::Config;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp;
|
||||
use Cwd qw(cwd realpath);
|
||||
use File::Basename;
|
||||
use File::Temp qw/ tempfile tempdir /;
|
||||
use Data::Dumper;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(
|
||||
read_config
|
||||
write_config
|
||||
find_first_file
|
||||
find_first_dir
|
||||
);
|
||||
|
||||
our $confdir = "/etc/apparmor";
|
||||
|
||||
# config vars
|
||||
our $cfg;
|
||||
our $repo_cfg;
|
||||
|
||||
sub read_config {
|
||||
my $filename = shift;
|
||||
my $config;
|
||||
|
||||
if (open(CONF, "$confdir/$filename")) {
|
||||
my $which;
|
||||
while (<CONF>) {
|
||||
chomp;
|
||||
# ignore comments
|
||||
next if /^\s*#/;
|
||||
if (m/^\[(\S+)\]/) {
|
||||
$which = $1;
|
||||
} elsif (m/^\s*(\S+)\s*=\s*(.*)\s*$/) {
|
||||
my ($key, $value) = ($1, $2);
|
||||
$config->{$which}{$key} = $value;
|
||||
}
|
||||
}
|
||||
close(CONF);
|
||||
}
|
||||
|
||||
# LP: #692406
|
||||
# Explicitly disable the repository until there is an alternative, since
|
||||
# the OpenSUSE site went away
|
||||
if ($filename eq "repository.conf") {
|
||||
$config->{repository}{enabled} = "no";
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub write_config {
|
||||
my ($filename, $config) = @_;
|
||||
if (open(my $CONF, ">$confdir/$filename")) {
|
||||
for my $section (sort keys %$config) {
|
||||
print $CONF "[$section]\n";
|
||||
|
||||
for my $key (sort keys %{$config->{$section}}) {
|
||||
print $CONF " $key = $config->{$section}{$key}\n"
|
||||
if ($config->{$section}{$key});
|
||||
}
|
||||
}
|
||||
chmod(0600, $CONF);
|
||||
close($CONF);
|
||||
} else {
|
||||
die "Can't write config file $filename: $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub find_first_file {
|
||||
my $list = shift;
|
||||
return if ( not defined $list );
|
||||
my $filename;
|
||||
for my $f (split(/\s+/, $list)) {
|
||||
if (-f $f) {
|
||||
$filename = $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
sub find_first_dir {
|
||||
my $list = shift;
|
||||
return if ( not defined $list );
|
||||
my $dirname;
|
||||
for my $f (split(/\s+/, $list)) {
|
||||
if (-d $f) {
|
||||
$dirname = $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return $dirname;
|
||||
}
|
||||
|
||||
1;
|
2024
deprecated/utils/Immunix/Reports.pm
Executable file
2024
deprecated/utils/Immunix/Reports.pm
Executable file
File diff suppressed because it is too large
Load Diff
354
deprecated/utils/Immunix/Repository.pm
Normal file
354
deprecated/utils/Immunix/Repository.pm
Normal file
@@ -0,0 +1,354 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2008 Dominic Reynolds
|
||||
#
|
||||
# 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 as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
package Immunix::Repository;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp;
|
||||
use Cwd qw(cwd realpath);
|
||||
use Data::Dumper;
|
||||
use File::Basename;
|
||||
use File::Temp qw/ tempfile tempdir /;
|
||||
use Immunix::Config;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use RPC::XML;
|
||||
use RPC::XML::Client;
|
||||
|
||||
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(
|
||||
get_repo_client
|
||||
did_result_succeed
|
||||
get_result_error
|
||||
user_login
|
||||
user_register
|
||||
upload_profile
|
||||
fetch_profile_by_id
|
||||
fetch_profiles_by_user
|
||||
fetch_profiles_by_name
|
||||
fetch_profiles_by_name_and_user
|
||||
fetch_newer_profile
|
||||
get_repo_config
|
||||
set_repo_config
|
||||
);
|
||||
|
||||
our %clients;
|
||||
our %uid2login;
|
||||
our $DEBUGGING = 0;
|
||||
our $repo_cfg;
|
||||
our $aa_cfg;
|
||||
|
||||
sub get_repo_client ($) {
|
||||
my $repo_url = shift;
|
||||
unless ( $clients{$repo_url} ) {
|
||||
$clients{$repo_url} = new RPC::XML::Client $repo_url;
|
||||
}
|
||||
return $clients{$repo_url};
|
||||
}
|
||||
|
||||
sub did_result_succeed {
|
||||
my $result = shift;
|
||||
|
||||
my $ref = ref $result;
|
||||
return ($ref && $ref ne "RPC::XML::fault") ? 1 : 0;
|
||||
}
|
||||
|
||||
sub get_result_error {
|
||||
my $result = shift;
|
||||
|
||||
if (ref $result) {
|
||||
if (ref $result eq "RPC::XML::fault") {
|
||||
$result = $result->string;
|
||||
} else {
|
||||
$result = $$result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub user_login ($$$) {
|
||||
my ($repo_url,$user,$pass) = @_;
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
if ( $repo_client ) {
|
||||
my $res = $repo_client->send_request('LoginConfirm', $user, $pass);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = "";
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
|
||||
sub user_register ($$$$) {
|
||||
my ($repo_url,$user,$pass,$email) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my ($status,$detail);
|
||||
if ( $repo_client ) {
|
||||
my $res = $repo_client->send_request('Signup', $user, $pass, $email);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = "";
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub upload_profile ($$$$$$$) {
|
||||
my ($repo_url,$user,$pass,$distro,$pname,$profile,$changelog) = @_;
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $res = $repo_client->send_request( 'Create', $user, $pass, $distro,
|
||||
$pname, $profile, $changelog);
|
||||
if (did_result_succeed($res)) {
|
||||
$detail = $res->value;
|
||||
$status = 1;
|
||||
} else {
|
||||
$detail = get_result_error($res);
|
||||
$status = 0;
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_profile_by_id ($$) {
|
||||
my ($repo_url,$id) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $repo_profile;
|
||||
my ($status,$detail);
|
||||
my $res = $repo_client->send_request('Show', $id);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = $res->value();
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
|
||||
return $status, $detail;
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles ($$$$) {
|
||||
my ($repo_url,$distro,$username,$fqdn) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $res =
|
||||
$repo_client->send_request('FindProfiles', $distro, $fqdn, $username);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
for my $p ( @$res ) {
|
||||
my $p_repo = $p->{profile}->value();
|
||||
$p_repo =~ s/flags=\(complain\)// if ( $p_repo ); #strip complain flag
|
||||
$p->{profile} = $p_repo;
|
||||
$p->{user_id} = $p->{user_id}->value();
|
||||
$p->{id} = $p->{id}->value();
|
||||
$p->{name} = $p->{name}->value();
|
||||
$p->{created_at} = $p->{created_at}->value();
|
||||
$p->{downloaded_count} = $p->{downloaded_count}->value();
|
||||
}
|
||||
$detail = $res;
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_profiles_by_user ($$$) {
|
||||
my ($repo_url,$distro,$username) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, "" );
|
||||
if ( $status ) {
|
||||
for my $p ( @$detail ) {
|
||||
my $p_repo = $p->{profile};
|
||||
if ($p_repo ne "") {
|
||||
$p->{username} = $username;
|
||||
$p_hash->{$p->{name}} = $p;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ($status,$detail);
|
||||
}
|
||||
return($status,$p_hash);
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles_by_name_and_user ($$$$) {
|
||||
my ($repo_url,$distro,$fqdbin, $username) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, $fqdbin );
|
||||
if ( $status ) {
|
||||
for my $p ( @$detail ) {
|
||||
my $p_repo = $p->{profile}?$p->{profile}:"";
|
||||
$p_hash->{$p->{name}} = $p if ($p_repo ne "");
|
||||
}
|
||||
} else {
|
||||
return ($status,$detail);
|
||||
}
|
||||
return($status,$p_hash);
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles_by_name ($$$) {
|
||||
my ($repo_url,$distro,$fqdbin) = @_;
|
||||
my ($status,$detail,$data);
|
||||
$detail = {};
|
||||
($status,$data) = fetch_profiles( $repo_url, $distro, "", $fqdbin);
|
||||
if ($status) {
|
||||
my @uids;
|
||||
for my $p (@$data) {
|
||||
push @uids, $p->{user_id};
|
||||
}
|
||||
my ($status_unames,$unames) = fetch_usernames_from_uids($repo_url, @uids);
|
||||
if ( $status_unames ) {
|
||||
for my $p (@$data) {
|
||||
if ( $unames->{$p->{user_id}} ) {
|
||||
$p->{username} = $unames->{$p->{user_id}};
|
||||
} else {
|
||||
$p->{username} = "unkown-" . $p->{user_id};
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
print STDOUT "ERROR UID\n";
|
||||
}
|
||||
for my $p (@$data) {
|
||||
$p->{profile_type} = "REPOSITORY";
|
||||
$detail->{$p->{username}} = $p;
|
||||
}
|
||||
} else {
|
||||
$detail = $data;
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
|
||||
sub fetch_newer_profile ($$$$$) {
|
||||
my ($repo_url,$distro,$user,$id,$profile) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $p;
|
||||
my ($status,$detail);
|
||||
|
||||
if ($repo_client) {
|
||||
my $res =
|
||||
$repo_client->send_request('FindProfiles', $distro, $profile, $user);
|
||||
if (did_result_succeed($res)) {
|
||||
my @profiles;
|
||||
my @profile_list = @{$res->value};
|
||||
$status = 1;
|
||||
|
||||
if (@profile_list) {
|
||||
if ($profile_list[0]->{id} > $id) {
|
||||
$p = $profile_list[0];
|
||||
}
|
||||
}
|
||||
$detail = $p;
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_usernames_from_uids ($) {
|
||||
my ($repo_url,@searchuids) = @_;
|
||||
my ($status,$result) = (1,{});
|
||||
my @uids;
|
||||
|
||||
for my $uid ( @searchuids ) {
|
||||
if ( $uid2login{$uid} ) {
|
||||
$result->{$uid} = $uid2login{$uid};
|
||||
} else {
|
||||
push @uids, $uid;
|
||||
}
|
||||
}
|
||||
if (@uids) {
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
#RPC::XML will serialize the array into XML with the is_utf8 flag set
|
||||
#which causes, HTTP:Message to fail. Looping on the array elements
|
||||
#stops this from happening, and since these are all numbers it
|
||||
#will not cause problems.
|
||||
for my $foo (@uids) {
|
||||
Encode::_utf8_off($foo);
|
||||
}
|
||||
my $res = $repo_client->send_request('LoginNamesFromUserIds', [@uids]);
|
||||
if (did_result_succeed($res)) {
|
||||
my @usernames = @{ $res->value };
|
||||
for my $uid (@uids) {
|
||||
my $username = shift @usernames;
|
||||
$uid2login{$uid} = $username;
|
||||
$result->{$uid} = $uid2login{$uid};
|
||||
}
|
||||
} else {
|
||||
$status = 0;
|
||||
$result = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$result;
|
||||
}
|
||||
|
||||
sub get_repo_config {
|
||||
unless ( $repo_cfg ) {
|
||||
$repo_cfg = Immunix::Config::read_config("repository.conf");
|
||||
}
|
||||
unless ( $aa_cfg ) {
|
||||
$aa_cfg = Immunix::Config::read_config("logprof.conf");
|
||||
}
|
||||
return {
|
||||
"url" => $aa_cfg->{repository}{url},
|
||||
"distro" => $aa_cfg->{repository}{distro},
|
||||
"enabled" => $repo_cfg->{repository}{enabled},
|
||||
"upload" => $repo_cfg->{repository}{upload},
|
||||
"user" => $repo_cfg->{repository}{user},
|
||||
"password" => $repo_cfg->{repository}{pass},
|
||||
"email" => $repo_cfg->{repository}{email}
|
||||
};
|
||||
}
|
||||
|
||||
sub set_repo_config ($) {
|
||||
my $cfg = shift;
|
||||
my ($url,$distro,$enabled,$upload,$user,$pass);
|
||||
unless ( $repo_cfg ) {
|
||||
$repo_cfg = Immunix::Config::read_config("repository.conf");
|
||||
}
|
||||
unless ( $aa_cfg ) {
|
||||
$aa_cfg = Immunix::Config::read_config("logprof.conf");
|
||||
}
|
||||
$repo_cfg->{repository}{enabled} = $cfg->{enabled} if ( $cfg->{enabled} );
|
||||
$repo_cfg->{repository}{upload} = $cfg->{upload} if ( $cfg->{upload} );
|
||||
$repo_cfg->{repository}{user} = $cfg->{user} if ( $cfg->{user} );
|
||||
$repo_cfg->{repository}{pass} = $cfg->{password}if ( $cfg->{password} );
|
||||
$repo_cfg->{repository}{email} = $cfg->{email} if ( $cfg->{email} );
|
||||
$aa_cfg->{repository}{distro} = $cfg->{distro} if ( $cfg->{distro} );
|
||||
$aa_cfg->{repository}{url} = $cfg->{url} if ( $cfg->{url} );
|
||||
write_config("repository.conf", $repo_cfg);
|
||||
write_config("logprof.conf", $aa_cfg);
|
||||
}
|
||||
|
||||
|
||||
1;
|
221
deprecated/utils/Immunix/Severity.pm
Normal file
221
deprecated/utils/Immunix/Severity.pm
Normal file
@@ -0,0 +1,221 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2005-2006 Novell/SUSE
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
package Immunix::Severity;
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
|
||||
my ($debug) = 0;
|
||||
|
||||
sub debug {
|
||||
print @_ if $debug;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $self = {};
|
||||
$self->{DATABASENAME} = undef;
|
||||
$self->{CAPABILITIES} = {};
|
||||
$self->{FILES} = {};
|
||||
$self->{REGEXPS} = {};
|
||||
$self->{DEFAULT_RANK} = 10;
|
||||
bless($self);
|
||||
shift;
|
||||
$self->init(@_) if @_;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub init ($;$) {
|
||||
my ($self, $resource, $read, $write, $execute, $severity);
|
||||
$self = shift;
|
||||
$self->{DATABASENAME} = shift;
|
||||
$self->{DEFAULT_RANK} = shift if defined $_[0];
|
||||
open(DATABASE, $self->{DATABASENAME})
|
||||
or die "Could not open severity db $self->{DATABASENAME}: $!\n";
|
||||
while (<DATABASE>) {
|
||||
chomp();
|
||||
next if m/^\s*#/;
|
||||
next if m/^\s*$/;
|
||||
|
||||
# leading whitespace is fine; maybe it shouldn't be?
|
||||
if (/^\s*\/(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/) {
|
||||
my ($path, $read, $write, $execute) = ($1, $2, $3, $4);
|
||||
|
||||
if (index($path, "*") == -1) {
|
||||
|
||||
$self->{FILES}{$path} = {
|
||||
r => $read,
|
||||
w => $write,
|
||||
x => $execute
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
my $ptr = $self->{REGEXPS};
|
||||
my @pieces = split(/\//, $path);
|
||||
|
||||
while (my $piece = shift @pieces) {
|
||||
if (index($piece, "*") != -1) {
|
||||
my $path = join("/", $piece, @pieces);
|
||||
my $regexp = convert_regexp($path);
|
||||
$ptr->{$regexp}{SD_RANK} = {
|
||||
r => $read,
|
||||
w => $write,
|
||||
x => $execute
|
||||
};
|
||||
last;
|
||||
} else {
|
||||
$ptr->{$piece} = {} unless exists $ptr->{$piece};
|
||||
$ptr = $ptr->{$piece};
|
||||
}
|
||||
}
|
||||
}
|
||||
} elsif (m|^\s*CAP|) {
|
||||
($resource, $severity) = split;
|
||||
$self->{CAPABILITIES}{$resource} = $severity;
|
||||
} else {
|
||||
print "unexpected database line: $_\n";
|
||||
}
|
||||
}
|
||||
close(DATABASE);
|
||||
debug Dumper($self);
|
||||
return $self;
|
||||
}
|
||||
|
||||
#rank:
|
||||
# handle capability
|
||||
# handle file
|
||||
#
|
||||
# handle capability
|
||||
# if the name is in the database, return it
|
||||
# otherwise, send a diagnostic message to stderr and return the default
|
||||
#
|
||||
# handle file
|
||||
# initialize the current return value to 0
|
||||
# loop over each entry in the database;
|
||||
# find the max() value for each mode that matches and set a 'found' flag
|
||||
# if the found flag has not been set, return the default;
|
||||
# otherwise, return the maximum from the database
|
||||
|
||||
sub handle_capability ($) {
|
||||
my ($self, $resource) = @_;
|
||||
|
||||
my $ret = $self->{CAPABILITIES}{$resource};
|
||||
if (!defined($ret)) {
|
||||
return "unexpected capability rank input: $resource\n";
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub check_subtree {
|
||||
my ($tree, $mode, $sev, $first, @rest) = @_;
|
||||
|
||||
# reassemble the remaining path from this directory level
|
||||
my $path = join("/", $first, @rest);
|
||||
|
||||
# first check if we have a literal directory match to descend into
|
||||
if ($tree->{$first}) {
|
||||
$sev = check_subtree($tree->{$first}, $mode, $sev, @rest);
|
||||
}
|
||||
|
||||
# if we didn't get a severity already, check for matching globs
|
||||
unless ($sev) {
|
||||
|
||||
# check each glob at this directory level
|
||||
for my $chunk (grep { index($_, "*") != -1 } keys %{$tree}) {
|
||||
|
||||
# does it match the rest of our path?
|
||||
if ($path =~ /^$chunk$/) {
|
||||
|
||||
# if we've got a ranking, check if it's higher than
|
||||
# current one, if any
|
||||
if ($tree->{$chunk}->{SD_RANK}) {
|
||||
for my $m (split(//, $mode)) {
|
||||
if ((!defined $sev)
|
||||
|| $tree->{$chunk}->{SD_RANK}->{$m} > $sev)
|
||||
{
|
||||
$sev = $tree->{$chunk}->{SD_RANK}->{$m};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sev;
|
||||
}
|
||||
|
||||
sub handle_file ($$) {
|
||||
my ($self, $resource, $mode) = @_;
|
||||
|
||||
# strip off the initial / from the path we're checking
|
||||
$resource = substr($resource, 1);
|
||||
|
||||
# break the path into directory-level chunks
|
||||
my @pieces = split(/\//, $resource);
|
||||
|
||||
my $sev;
|
||||
|
||||
# if there's a exact match for this path in the db, use that instead of
|
||||
# checking the globs
|
||||
if ($self->{FILES}{$resource}) {
|
||||
|
||||
# check each piece of the passed mode against the db entry
|
||||
for my $m (split(//, $mode)) {
|
||||
if ((!defined $sev) || $self->{FILES}{$resource}{$m} > $sev) {
|
||||
$sev = $self->{FILES}{$resource}{$m};
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
# descend into the regexp tree looking for matches
|
||||
$sev = check_subtree($self->{REGEXPS}, $mode, $sev, @pieces);
|
||||
|
||||
}
|
||||
|
||||
return (defined $sev) ? $sev : $self->{DEFAULT_RANK};
|
||||
}
|
||||
|
||||
sub rank ($;$) {
|
||||
my ($self, $resource, $mode) = @_;
|
||||
|
||||
if (substr($resource, 0, 1) eq "/") {
|
||||
return $self->handle_file($resource, $mode);
|
||||
} elsif (substr($resource, 0, 3) eq "CAP") {
|
||||
return $self->handle_capability($resource);
|
||||
} else {
|
||||
return "unexpected rank input: $resource\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub convert_regexp ($) {
|
||||
my ($input) = shift;
|
||||
|
||||
# we need to convert subdomain regexps to perl regexps
|
||||
my $regexp = $input;
|
||||
|
||||
# escape + . [ and ] characters
|
||||
$regexp =~ s/(\+|\.|\[|\])/\\$1/g;
|
||||
|
||||
# convert ** globs to match anything
|
||||
$regexp =~ s/\*\*/.SDPROF_INTERNAL_GLOB/g;
|
||||
|
||||
# convert * globs to match anything at current path level
|
||||
$regexp =~ s/\*/[^\/]SDPROF_INTERNAL_GLOB/g;
|
||||
|
||||
# convert {foo,baz} to (foo|baz)
|
||||
$regexp =~ y/\{\}\,/\(\)\|/ if $regexp =~ /\{.*\,.*\}/;
|
||||
|
||||
# twiddle the escaped * chars back
|
||||
$regexp =~ s/SDPROF_INTERNAL_GLOB/\*/g;
|
||||
return $regexp;
|
||||
}
|
||||
|
||||
1; # so the require or use succeeds
|
62
deprecated/utils/Makefile
Normal file
62
deprecated/utils/Makefile
Normal file
@@ -0,0 +1,62 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2004-2009 NOVELL (All rights reserved)
|
||||
# Copyright (c) 2010-2011, 2014 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.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# NOTE: this Makefile has been adjusted from the original to assist in
|
||||
# the installation of the Immunix perl modules, if they're still needed
|
||||
# by users. Because the utilities conflict with their replacments, make
|
||||
# install *will* *not* install them.
|
||||
|
||||
NAME = apparmor-utils
|
||||
all:
|
||||
COMMONDIR=../../common/
|
||||
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
MODDIR = Immunix
|
||||
PERLTOOLS = aa-genprof aa-logprof aa-autodep aa-audit aa-complain aa-enforce \
|
||||
aa-unconfined aa-disable
|
||||
MODULES = ${MODDIR}/AppArmor.pm ${MODDIR}/Repository.pm \
|
||||
${MODDIR}/Config.pm ${MODDIR}/Severity.pm
|
||||
|
||||
all:
|
||||
|
||||
# need some better way of determining this
|
||||
DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/sbin
|
||||
CONFDIR=${DESTDIR}/etc/apparmor
|
||||
VENDOR_PERL=$(shell perl -e 'use Config; print $$Config{"vendorlib"};')
|
||||
PERLDIR=${DESTDIR}${VENDOR_PERL}/${MODDIR}
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
install -d ${PERLDIR}
|
||||
install -m 644 ${MODULES} ${PERLDIR}
|
||||
|
||||
.PHONY: clean
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
endif
|
||||
clean: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~
|
||||
rm -rf staging/ build/
|
||||
|
||||
.PHONY: check
|
||||
.SILENT: check
|
||||
check:
|
||||
for i in ${MODULES} ${PERLTOOLS} ; do \
|
||||
perl -c $$i || exit 1; \
|
||||
done
|
132
deprecated/utils/aa-audit
Executable file
132
deprecated/utils/aa-audit
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 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 as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString("Please enter the program to switch to audit mode: ", ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to audit mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "audit");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to audit mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
122
deprecated/utils/aa-autodep
Executable file
122
deprecated/utils/aa-autodep
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 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 as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $force = undef;
|
||||
|
||||
GetOptions(
|
||||
'force' => \$force,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important(sprintf(gettext('Can\'t find AppArmor profiles in %s.'), $profiledir));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to create a profile for: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
if ($qualifiers{$fqdbin}) {
|
||||
unless ($qualifiers{$fqdbin} =~ /p/) {
|
||||
UI_Info(sprintf(gettext('%s is currently marked as a program that should not have it\'s own profile. Usually, programs are marked this way if creating a profile for them is likely to break the rest of the system. If you know what you\'re doing and are certain you want to create a profile for this program, edit the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf.'), $fqdbin));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
if (-e getprofilefilename($fqdbin) && !$force) {
|
||||
UI_Info(sprintf(gettext('Profile for %s already exists - skipping.'), $fqdbin));
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
reload($fqdbin) if $sd_mountpoint;
|
||||
}
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info("usage: $0 [ --force ] [ -d /path/to/profiles ]");
|
||||
exit 0;
|
||||
}
|
||||
|
131
deprecated/utils/aa-complain
Executable file
131
deprecated/utils/aa-complain
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to complain mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to complain mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "complain");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to complain mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
152
deprecated/utils/aa-disable
Executable file
152
deprecated/utils/aa-disable
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005-2010 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Canonical, Inc.
|
||||
#
|
||||
# To contact Canonical about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.canonical.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use File::Basename;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $disabledir = "$profiledir/disable";
|
||||
unless (-d $disabledir) {
|
||||
UI_Important("Can't find AppArmor disable directory '$disabledir'.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program whose profile should be disabled: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip package manager backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
my ($bname, $dname, $suffix) = File::Basename::fileparse($filename);
|
||||
if ($bname eq "") {
|
||||
UI_Info(sprintf(gettext('Could not find basename for %s.'), $filename));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
printf(gettext('Disabling %s.'), $fqdbin);
|
||||
print "\n";
|
||||
|
||||
my $link = "$disabledir/$bname";
|
||||
if (! -e $link) {
|
||||
if (symlink($filename, $link) != 1) {
|
||||
UI_Info(sprintf(gettext('Could not create %s symlink.'), $link));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -R 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to have profile disabled ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
142
deprecated/utils/aa-enforce
Executable file
142
deprecated/utils/aa-enforce
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 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 as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to enforce mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to enforce mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "");
|
||||
|
||||
# remove symlink in $profiledir/force-complain as well
|
||||
my $complainlink = $filename;
|
||||
$complainlink =~ s/^$profiledir/$profiledir\/force-complain/;
|
||||
-e $complainlink and unlink($complainlink);
|
||||
|
||||
# remove symlink in $profiledir/disable as well
|
||||
my $disablelink = $filename;
|
||||
$disablelink =~ s/^$profiledir/$profiledir\/disable/;
|
||||
-e $disablelink and unlink($disablelink);
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to enforce mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
940
deprecated/utils/aa-eventd
Executable file
940
deprecated/utils/aa-eventd
Executable file
@@ -0,0 +1,940 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
|
||||
use Data::Dumper;
|
||||
use DBI;
|
||||
use Fcntl;
|
||||
use File::Temp qw(tempfile);
|
||||
use Getopt::Long;
|
||||
use POSIX 'setsid';
|
||||
use Time::Local;
|
||||
use File::Tail;
|
||||
|
||||
use Immunix::Severity;
|
||||
require LibAppArmor;
|
||||
|
||||
##########################################################################
|
||||
# locations
|
||||
|
||||
my $productname = "apparmor";
|
||||
|
||||
my $cfgdir = "/etc/$productname";
|
||||
my $dbdir = "/var/log/$productname";
|
||||
|
||||
my $cfgfile = "$cfgdir/notify.cfg";
|
||||
my $errlog = "$dbdir/event-dispatch.log";
|
||||
|
||||
my $logfile = "/var/log/audit/audit.log";
|
||||
my $syslogfile = "/var/log/messages";
|
||||
|
||||
##########################################################################
|
||||
|
||||
# options variables
|
||||
my $pidfile = '';
|
||||
|
||||
GetOptions('pidfile|p=s' => \$pidfile);
|
||||
|
||||
my $DEBUG = 0;
|
||||
|
||||
my $config;
|
||||
|
||||
my $verbose = { last_notify => 0 };
|
||||
my $summary = { last_notify => 0 };
|
||||
my $terse = { last_notify => 0 };
|
||||
|
||||
# we don't want to call str2time on every line and also batch up event dbs
|
||||
# a month at a time, so we need to keep track of a few extra things
|
||||
my $timestamp = 0;
|
||||
my $lasttime = "";
|
||||
my $counter = 0;
|
||||
my $thismonth = 0;
|
||||
my $nextmonth = 0;
|
||||
|
||||
# pop open a connection to the severity database
|
||||
my $sevdb = new Immunix::Severity("$cfgdir/severity.db", -1);
|
||||
|
||||
my $REdate = '\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}';
|
||||
|
||||
my $last_inserted_time;
|
||||
my $last_inserted_counter;
|
||||
|
||||
##########################################################################
|
||||
|
||||
# commit how often?
|
||||
my $timeout = 5;
|
||||
|
||||
# keep track of when we commited last
|
||||
my $last_flush_time = 0;
|
||||
|
||||
# keep track of some statistics
|
||||
my $max = 0;
|
||||
my $inserts = 0;
|
||||
my $total = 0;
|
||||
|
||||
my @commit_buffer;
|
||||
my @debug_buffer;
|
||||
|
||||
my @verbose_buffer;
|
||||
my @summary_buffer;
|
||||
my @terse_buffer;
|
||||
|
||||
my $date_module = "None";
|
||||
|
||||
my %templates = (
|
||||
"path" => "(time,counter,type,op,profile,sdmode,mode_req,mode_deny,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"link" => "(time,counter,type,op,profile,sdmode,resource,target,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"chattr" => "(time,counter,type,op,profile,sdmode,resource,mode_req,mode_deny,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"capability" => "(time,counter,type,op,profile,sdmode,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?)",
|
||||
"capable" => "(time,counter,type,op,prog,pid,profile) VALUES(?,?,?,?,?,?,?)",
|
||||
"unknown_hat" => "(time,counter,type,op,profile,sdmode,resource,pid) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"fork" => "(time,counter,type,op,profile,sdmode,pid,resource) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"changing_profile" => "(time,counter,type,op,profile,sdmode,pid) VALUES(?,?,?,?,?,?,?)",
|
||||
"profile_replacement" => "(time,counter,type,op,profile,sdmode,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?)",
|
||||
"net" => "(time,counter,type,op,net_family,net_socktype,net_proto,pid,profile) VALUES(?,?,?,?,?,?,?,?,?)",
|
||||
"removed" => "(time,counter,type,op,severity) VALUES(?,?,?,?,?)",
|
||||
"initialized" => "(time,counter,type,op,resource,severity) VALUES(?,?,?,?,?,?)",
|
||||
"ctrl_var" => "(time,counter,type,op,resource,mode_req,mode_deny,severity) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"profile_load" => "(time,counter,type,op,resource,prog,pid) VALUES(?,?,?,?,?,?,?)",
|
||||
);
|
||||
|
||||
##########################################################################
|
||||
# generic functions
|
||||
|
||||
sub errlog ($) {
|
||||
my $mesg = shift;
|
||||
my $localtime = localtime(time);
|
||||
print ERRLOG "[$localtime] $mesg\n";
|
||||
}
|
||||
|
||||
sub readconfig () {
|
||||
my $cfg = {};
|
||||
|
||||
# record when we read the config file
|
||||
$cfg->{load_time} = time;
|
||||
|
||||
if (open(CFG, $cfgfile)) {
|
||||
|
||||
# yank in the values we need
|
||||
while (<CFG>) {
|
||||
$cfg->{$1} = $2 if /^(\S+)\s+(.+)\s*$/;
|
||||
}
|
||||
close(CFG);
|
||||
}
|
||||
|
||||
return $cfg;
|
||||
}
|
||||
|
||||
sub daemonize {
|
||||
chdir '/' or die "Can't chdir to /: $!";
|
||||
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
|
||||
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
|
||||
defined(my $pid = fork) or die "Can't fork: $!";
|
||||
exit if $pid;
|
||||
setsid or die "Can't start a new session: $!";
|
||||
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
|
||||
}
|
||||
|
||||
sub parsedate ($) {
|
||||
my $time = shift;
|
||||
my $timestamp = 0;
|
||||
if ($date_module eq 'TimeDate') {
|
||||
$timestamp = Date::Parse::str2time($time);
|
||||
} elsif ($date_module eq 'DateManip') {
|
||||
$timestamp = Date::Manip::UnixDate(Date::Manip::ParseDateString($time), '%s');
|
||||
} else {
|
||||
errlog "No date module found, exiing";
|
||||
kill HUP => -$$;
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# database handling functions
|
||||
|
||||
sub connect_database ($) {
|
||||
my $dbdir = shift;
|
||||
|
||||
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbdir/events.db", "", "", {RaiseError=>1});
|
||||
|
||||
# we'll do the commits ourselves so performance doesn't suck
|
||||
$dbh->{AutoCommit} = 0;
|
||||
|
||||
# bump up our cache size a little
|
||||
$dbh->do("PRAGMA cache_size = 20000;");
|
||||
|
||||
# figure out if the tables already exist or not
|
||||
my %existing_tables;
|
||||
my $sth = $dbh->prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
|
||||
$sth->execute;
|
||||
while (my @row = $sth->fetchrow_array) {
|
||||
$existing_tables{ $row[0] } = 1;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
# create the info table and fill in the appropriate values for this db
|
||||
unless ($existing_tables{info}) {
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
$dbh->do("CREATE TABLE info (name,value)");
|
||||
$sth = $dbh->prepare("INSERT INTO info(name,value) VALUES(?,?)");
|
||||
$sth->execute("version", "0.2");
|
||||
$sth->execute("host", "$host");
|
||||
}
|
||||
|
||||
# create the events table
|
||||
unless ($existing_tables{events}) {
|
||||
$dbh->do(
|
||||
"CREATE TABLE events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
time INTEGER NOT NULL,
|
||||
counter INTEGER NOT NULL,
|
||||
op,
|
||||
pid,
|
||||
sdmode,
|
||||
type,
|
||||
mode_deny,
|
||||
mode_req,
|
||||
resource,
|
||||
target,
|
||||
profile,
|
||||
prog,
|
||||
name_alt,
|
||||
attr,
|
||||
parent,
|
||||
active_hat,
|
||||
net_family,
|
||||
net_proto,
|
||||
net_socktype,
|
||||
severity INTEGER
|
||||
)"
|
||||
);
|
||||
|
||||
# set up the indexes we want
|
||||
#my @indexes = qw(time type sdmode mode resource profile prog severity);
|
||||
my @indexes = qw(time type op sdmode mode_req mode_deny resource profile prog severity);
|
||||
for my $index (@indexes) {
|
||||
$dbh->do("CREATE INDEX " . $index . "_idx ON events($index)");
|
||||
}
|
||||
}
|
||||
# make sure our changes actually get saved
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
|
||||
# mark the db as up to date as of now
|
||||
$last_flush_time = time;
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
|
||||
sub verbose_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my $subj = "Verbose Security Report for $host.";
|
||||
my $mesg = "The following security events occured since $last:\n\n";
|
||||
|
||||
my @events;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$mesg .= "$logmsg\n";
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if (@events) {
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "[$count events] sending verbose notification to $email.";
|
||||
}
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the verbose notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub summary_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my $subj = "Summary Security Report for $host.";
|
||||
my $mesg = "The following security events occured since $last:\n\n";
|
||||
|
||||
my @events;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$mesg .= "$logmsg\n";
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if (@events) {
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "[$count events] sending summary notification to $email.";
|
||||
}
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the verbose notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub terse_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my @events;
|
||||
my $count = 0;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if ($count) {
|
||||
if ($DEBUG) {
|
||||
errlog "[$count events] sending terse notification to $email.";
|
||||
}
|
||||
my $subj = "Security Report for $host.";
|
||||
my $mesg = "$host has had $count security events since $last.";
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the terse notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub fork_into_background {
|
||||
my ($name, $func, @args) = @_;
|
||||
|
||||
my $pid = fork;
|
||||
|
||||
if (not defined $pid) {
|
||||
|
||||
# something bad happened, just log it...
|
||||
errlog "couldn't fork for \"$name\": $!"
|
||||
|
||||
} elsif ($pid == 0) {
|
||||
|
||||
# we're in the child process now...
|
||||
|
||||
# set our process name
|
||||
$0 = $name;
|
||||
|
||||
# call our subroutine
|
||||
my $ret = &$func(@args);
|
||||
|
||||
exit($ret);
|
||||
}
|
||||
|
||||
return $pid;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# Parse event record into key-value pairs
|
||||
sub parseEvent($) {
|
||||
|
||||
my %ev = ();
|
||||
my $msg = shift;
|
||||
chomp($msg);
|
||||
|
||||
my $event = LibAppArmor::parse_record($msg);
|
||||
|
||||
# resource is an alternate term for 'name1' below
|
||||
# mode is an alternate term for 'mode_deny' below
|
||||
$ev{'time'} = LibAppArmor::aa_log_record::swig_epoch_get($event);
|
||||
$ev{'op'} = LibAppArmor::aa_log_record::swig_operation_get($event);
|
||||
$ev{'pid'} = LibAppArmor::aa_log_record::swig_pid_get($event);
|
||||
$ev{'mode_deny'} = LibAppArmor::aa_log_record::swig_denied_mask_get($event);
|
||||
$ev{'mode_req'} = LibAppArmor::aa_log_record::swig_requested_mask_get($event);
|
||||
$ev{'profile'}= LibAppArmor::aa_log_record::swig_profile_get($event);
|
||||
$ev{'prog'} = LibAppArmor::aa_log_record::swig_name_get($event);
|
||||
$ev{'name2'} = LibAppArmor::aa_log_record::swig_name2_get($event);
|
||||
$ev{'attr'} = LibAppArmor::aa_log_record::swig_attribute_get($event);
|
||||
$ev{'parent'} = LibAppArmor::aa_log_record::swig_parent_get($event);
|
||||
$ev{'magic_token'} = LibAppArmor::aa_log_record::swig_magic_token_get($event);
|
||||
$ev{'resource'} = LibAppArmor::aa_log_record::swig_info_get($event);
|
||||
$ev{'active_hat'} = LibAppArmor::aa_log_record::swig_active_hat_get($event);
|
||||
$ev{'sdmode'} = LibAppArmor::aa_log_record::swig_event_get($event);
|
||||
|
||||
# NetDomain
|
||||
if ( $ev{'op'} && $ev{'op'} =~ /socket/ ) {
|
||||
next if $ev{'op'} =~ /create/;
|
||||
$ev{'net_family'} = LibAppArmor::aa_log_record::swig_net_family_get($event);
|
||||
$ev{'net_proto'} = LibAppArmor::aa_log_record::swig_net_protocol_get($event);
|
||||
$ev{'net_socktype'} = LibAppArmor::aa_log_record::swig_net_sock_type_get($event);
|
||||
}
|
||||
|
||||
LibAppArmor::free_record($event);
|
||||
|
||||
if ( ! $ev{'time'} ) { $ev{'time'} = time; }
|
||||
|
||||
# remove null responses
|
||||
for (keys(%ev)) {
|
||||
if ( ! $ev{$_} || $ev{$_} !~ /\w+/) {delete($ev{$_}); }
|
||||
#errlog "EVENT: $_ is $ev{$_}";
|
||||
}
|
||||
|
||||
if ( $ev{'sdmode'} ) {
|
||||
#0 = invalid, 1 = error, 2 = AUDIT, 3 = ALLOW/PERMIT,
|
||||
#4 = DENIED/REJECTED, 5 = HINT, 6 = STATUS/config change
|
||||
if ( $ev{'sdmode'} == 2 ) { $ev{'sdmode'} = "AUDITING"; }
|
||||
elsif ( $ev{'sdmode'} == 3 ) { $ev{'sdmode'} = "PERMITING"; }
|
||||
elsif ( $ev{'sdmode'} == 4 ) { $ev{'sdmode'} = "REJECTING"; }
|
||||
else { delete($ev{'sdmode'}); }
|
||||
}
|
||||
|
||||
return \%ev;
|
||||
}
|
||||
|
||||
sub process_event ($$) {
|
||||
|
||||
my $dbh = shift;
|
||||
my $logmsg = shift;
|
||||
my $sth;
|
||||
my $severity = "";
|
||||
my @eventList = ();
|
||||
my $type = undef;
|
||||
my $time = undef;
|
||||
|
||||
return unless $logmsg && $logmsg =~ /APPARMOR/;
|
||||
my $ev = parseEvent($logmsg);
|
||||
|
||||
# skip logprof hints
|
||||
if ( ! $ev->{'op'} || $ev->{'op'} eq 'clone') { return; }
|
||||
|
||||
$time = time; # XXX - do we want current time or $ev->{'time'}?
|
||||
|
||||
if ($time ne $lasttime) {
|
||||
$counter = 0;
|
||||
$timestamp = $time;
|
||||
$lasttime = $time;
|
||||
}
|
||||
|
||||
$counter++;
|
||||
|
||||
# some statistics...
|
||||
$max = $counter if $counter > $max;
|
||||
|
||||
# if we already have events in the db, make sure we don't try to re-enter
|
||||
# duplicates if we start up again and parse the same logfile over again
|
||||
if ($last_inserted_time) {
|
||||
return if $timestamp < $last_inserted_time;
|
||||
|
||||
if ($timestamp == $last_inserted_time) {
|
||||
return if $counter <= $last_inserted_counter;
|
||||
}
|
||||
|
||||
$last_inserted_time = undef;
|
||||
}
|
||||
|
||||
if ( $ev->{'sdmode'} && $ev->{'sdmode'} eq "REJECTING") {
|
||||
$severity = $sevdb->rank($ev->{'prog'}, $ev->{'mode_req'});
|
||||
if ( ! $severity ) { $severity = "-1"; }
|
||||
|
||||
# we only do notification for enforce mode events
|
||||
if ($config->{verbose_freq}) {
|
||||
if ( ($severity >= $config->{verbose_level})
|
||||
|| (($severity == -1) && $config->{verbose_unknown}))
|
||||
{
|
||||
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{summary_freq}) {
|
||||
if ( ($severity >= $config->{summary_level})
|
||||
|| (($severity == -1) && $config->{summary_unknown}))
|
||||
{
|
||||
push @summary_buffer, [ $timestamp, $counter, "path",
|
||||
$ev->{'prog'}, $ev->{'mode_req'}, $ev->{'resource'} ];
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{terse_freq}) {
|
||||
if ( ($severity >= $config->{terse_level})
|
||||
|| (($severity == -1) && $config->{terse_unknown}))
|
||||
{
|
||||
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unless ( $ev->{'op'} ) {
|
||||
my $errmsg = "ERROR: No operation found: ";
|
||||
for my $k (sort keys(%$ev)) {
|
||||
$errmsg .= "$k is $ev->{$k}, ";
|
||||
}
|
||||
errlog("$errmsg\n");
|
||||
return;
|
||||
}
|
||||
|
||||
# Format the message to match the db template
|
||||
if ($ev->{'op'} eq 'link' ) {
|
||||
$type = 'link';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'target'},$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'attribute') {
|
||||
$type = 'chattr';
|
||||
push(@eventList, []);
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'prog'},
|
||||
$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'capability') {
|
||||
$type = 'capability';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'capable') {
|
||||
$type = 'capable';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'prog'},
|
||||
$ev->{'profile'},$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} =~ /ontrol variable/ ) {
|
||||
$type = 'ctrl_var';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
|
||||
$ev->{'mode_req'},$ev->{'mode_deny'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'unknown_hat') {
|
||||
$type = 'unknown_hat';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'fork') {
|
||||
$type = 'fork';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'pid'},$ev->{'resource'}]);
|
||||
} elsif ($ev->{'op'} eq 'changing_profile') {
|
||||
$type = 'changing_profile';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} eq 'profile_load') {
|
||||
$type = 'profile_load';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
|
||||
$ev->{'prog'},$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} eq 'profile_replace') {
|
||||
$type = 'profile_replacement';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'removed') {
|
||||
$type = 'removed';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'initialized') {
|
||||
$type = 'initialized';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},$severity]);
|
||||
} elsif ( $ev->{'op'} =~ /socket/) {
|
||||
$type = 'net';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'net_family'},
|
||||
$ev->{'net_sock_type'},$ev->{'net_proto'},$ev->{'pid'},$ev->{'profile'}]);
|
||||
} else {
|
||||
$type = 'path';
|
||||
if ( ! $ev->{'prog'} ) { $ev->{'prog'} = "NIL"; }
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},
|
||||
$ev->{'sdmode'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'resource'},
|
||||
$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
}
|
||||
|
||||
push(@commit_buffer, @eventList);
|
||||
$inserts++;
|
||||
|
||||
}
|
||||
|
||||
sub dump_events {
|
||||
my ($which, @events) = @_;
|
||||
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "dumping $count events to $which db.";
|
||||
}
|
||||
|
||||
if (open(F, ">>$dbdir/$which.db")) {
|
||||
for my $event (@events) {
|
||||
my @event = @$event;
|
||||
print F "@event\n";
|
||||
}
|
||||
close(F);
|
||||
} else {
|
||||
errlog "can't write to $dbdir/$which.db: $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub check_timers ($) {
|
||||
my $dbh = shift;
|
||||
|
||||
# what time is it right... NOW
|
||||
my $now = time;
|
||||
|
||||
# make sure we commit periodically
|
||||
if (($inserts > 10000) || ($now >= ($last_flush_time + $timeout))) {
|
||||
|
||||
my $last_prepare = "";
|
||||
my $sth;
|
||||
|
||||
for my $event (sort { $a->[0] cmp $b->[0] } @commit_buffer) {
|
||||
my @event = @{$event};
|
||||
|
||||
#my $type = shift @event;
|
||||
my $type = $event[2];
|
||||
|
||||
eval {
|
||||
if ($type ne $last_prepare) {
|
||||
$sth = $dbh->prepare("INSERT INTO events $templates{$type}");
|
||||
$last_prepare = $type;
|
||||
}
|
||||
|
||||
$sth->execute(@event);
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
print ERRLOG "DBI Execution failed: $DBI::errstr\n";
|
||||
}
|
||||
|
||||
#$sth->execute(@event);
|
||||
}
|
||||
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
|
||||
# need to get the time again to include how much time it takes to
|
||||
# actually write all this crap to the db
|
||||
$now = time;
|
||||
|
||||
if ($DEBUG && $inserts) {
|
||||
$total += $inserts;
|
||||
my $delta = $now - $last_flush_time;
|
||||
my $rate = int($inserts / $delta);
|
||||
errlog "$rate/s $inserts in ${delta}s total=$total max=$max";
|
||||
}
|
||||
|
||||
$last_flush_time = $now;
|
||||
|
||||
@commit_buffer = ();
|
||||
|
||||
$max = 0;
|
||||
$inserts = 0;
|
||||
|
||||
if (@verbose_buffer) {
|
||||
|
||||
# if we've got verbose events, dump them
|
||||
dump_events("verbose", @verbose_buffer);
|
||||
|
||||
# and clear out our buffer
|
||||
@verbose_buffer = ();
|
||||
}
|
||||
|
||||
if (@terse_buffer) {
|
||||
|
||||
# if we've got terse events, dump them
|
||||
dump_events("terse", @terse_buffer);
|
||||
|
||||
# and clear out our buffer
|
||||
@terse_buffer = ();
|
||||
}
|
||||
|
||||
# bail out if we don't have notification configured
|
||||
return unless -f $cfgfile;
|
||||
|
||||
# what time did we last read the config file?
|
||||
my $load_time = $config->{load_time};
|
||||
|
||||
# check when the config file was last modified...
|
||||
my $mtime = (stat($cfgfile))[9];
|
||||
|
||||
# if it's been changed since we last read the config file, we need to
|
||||
# load the new settings
|
||||
if ($load_time < $mtime) {
|
||||
errlog "Reloading changed config file.";
|
||||
$config = readconfig();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# bail out if we don't have notification configured
|
||||
return unless -f $cfgfile;
|
||||
|
||||
if ($config->{terse_freq}) {
|
||||
if (($terse->{last_notify} + $config->{terse_freq}) <= $now) {
|
||||
if (-f "$dbdir/terse.db") {
|
||||
$DEBUG && errlog "doing terse notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("terseXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/terse.db", $filename);
|
||||
|
||||
if ($DEBUG) {
|
||||
errlog "terse file is $filename";
|
||||
}
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("terse-notification",
|
||||
\&terse_notify_handler,
|
||||
$config->{terse_email},
|
||||
$filename,
|
||||
$terse->{last_notify},
|
||||
$config->{terse_level},
|
||||
$config->{terse_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$terse->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{summary_freq}) {
|
||||
if (($summary->{last_notify} + $config->{summary_freq}) <= $now) {
|
||||
if (-f "$dbdir/summary.db") {
|
||||
$DEBUG && errlog "doing summary notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("summaryXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/summary.db", $filename);
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("summary-notification",
|
||||
\&summary_notify_handler,
|
||||
$config->{summary_email},
|
||||
$filename,
|
||||
$summary->{last_notify},
|
||||
$config->{summary_level},
|
||||
$config->{summary_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$summary->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{verbose_freq}) {
|
||||
if (($verbose->{last_notify} + $config->{verbose_freq}) <= $now) {
|
||||
if (-f "$dbdir/verbose.db") {
|
||||
$DEBUG && errlog "doing verbose notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("verboseXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/verbose.db", $filename);
|
||||
|
||||
if ($DEBUG) {
|
||||
errlog "verbose file is $filename";
|
||||
}
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("verbose-notification",
|
||||
\&verbose_notify_handler,
|
||||
$config->{verbose_email},
|
||||
$filename,
|
||||
$verbose->{last_notify},
|
||||
$config->{verbose_level},
|
||||
$config->{verbose_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$verbose->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub get_last_event {
|
||||
my $dbh = shift;
|
||||
|
||||
my ($time, $counter);
|
||||
|
||||
# get the oldest timestamp...
|
||||
my $sth = $dbh->prepare('SELECT MAX(time) FROM events');
|
||||
$sth->execute;
|
||||
my @row = $sth->fetchrow_array || (0);
|
||||
$time = $row[0];
|
||||
if ($time) {
|
||||
|
||||
# get the highest counter for this timestamp...
|
||||
$sth = $dbh->prepare("SELECT MAX(counter) FROM events WHERE time = $time");
|
||||
$sth->execute;
|
||||
@row = $sth->fetchrow_array || (0);
|
||||
$counter = $row[0];
|
||||
}
|
||||
|
||||
return ($time, $counter);
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# start the real magic...
|
||||
|
||||
my $finished;
|
||||
|
||||
# make sure we exit if someone sends us the right signal
|
||||
sub sig_handler {
|
||||
my $signame = shift;
|
||||
|
||||
errlog("Caught signal '$signame'. Exiting...");
|
||||
$finished = 1;
|
||||
}
|
||||
|
||||
# set up our error log without buffering
|
||||
open(ERRLOG, ">>$dbdir/event-dispatch.log");
|
||||
my $oldfd = select(ERRLOG);
|
||||
$| = 1;
|
||||
select($oldfd);
|
||||
|
||||
$config = readconfig();
|
||||
|
||||
# fork off into the background. we need to do this before we connect to
|
||||
# the db, otherwise, we'll get an ugly error about rolling back a
|
||||
# connection that's being destroyed
|
||||
daemonize;
|
||||
|
||||
# automagically reap child processes
|
||||
$SIG{INT} = \&sig_handler;
|
||||
$SIG{TERM} = \&sig_handler;
|
||||
$SIG{CHLD} = 'IGNORE';
|
||||
|
||||
# Sigh, portable dates in perl sucks
|
||||
eval "use Date::Parse";
|
||||
if (!$@) {
|
||||
$date_module = 'TimeDate';
|
||||
} else {
|
||||
eval "use Date::Manip";
|
||||
if (!$@) {
|
||||
$date_module = 'DateManip';
|
||||
} else {
|
||||
errlog "Unable to load Date module; use either TimeDate or Date::Manip";
|
||||
$finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# if they want us to write a pid, do it
|
||||
if ($pidfile) {
|
||||
if (open(PIDFILE, ">$pidfile")) {
|
||||
print PIDFILE "$$\n";
|
||||
close(PIDFILE);
|
||||
}
|
||||
}
|
||||
|
||||
my $dbh = connect_database($dbdir);
|
||||
|
||||
($last_inserted_time, $last_inserted_counter) = get_last_event($dbh);
|
||||
|
||||
my $auditlog = File::Tail->new(
|
||||
name => $logfile,
|
||||
debug => 1,
|
||||
tail => -1,
|
||||
interval => 1,
|
||||
maxinterval => 5,
|
||||
adjustafter => 20,
|
||||
errmode => "return",
|
||||
ignore_noexistant => 1
|
||||
);
|
||||
my $syslog = File::Tail->new(
|
||||
name => $syslogfile,
|
||||
debug => 1,
|
||||
tail => -1,
|
||||
interval => 1,
|
||||
maxinterval => 5,
|
||||
adjustafter => 20,
|
||||
errmode => "return",
|
||||
ignore_noexistant => 1
|
||||
);
|
||||
my $line = '';
|
||||
|
||||
# process complete lines from the buffer...
|
||||
while (not $finished) {
|
||||
my ($nfound, $timeleft, @pending) = File::Tail::select(undef, undef, undef, $timeout, ($auditlog, $syslog));
|
||||
|
||||
foreach (@pending) {
|
||||
process_event($dbh, $_->read);
|
||||
}
|
||||
|
||||
# see if we should flush pending entries to disk and/or do notification
|
||||
check_timers($dbh);
|
||||
}
|
||||
|
||||
# make sure we don't exit with any pending events not written to the db
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
$dbh->disconnect || errlog "Error disconnecting from db: $!";
|
||||
|
||||
# close our error/debugging log file
|
||||
close(ERRLOG);
|
||||
|
||||
unlink($pidfile) if $pidfile;
|
||||
|
||||
exit 0;
|
216
deprecated/utils/aa-genprof
Executable file
216
deprecated/utils/aa-genprof
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
sub sysctl_read($) {
|
||||
my $path = shift;
|
||||
my $value = undef;
|
||||
if (open(SYSCTL, "<$path")) {
|
||||
$value = int(<SYSCTL>);
|
||||
}
|
||||
close(SYSCTL);
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub sysctl_write($$) {
|
||||
my $path = shift;
|
||||
my $value = shift;
|
||||
return if (!defined($value));
|
||||
if (open(SYSCTL, ">$path")) {
|
||||
print SYSCTL $value;
|
||||
close(SYSCTl);
|
||||
}
|
||||
}
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
unless ($sd_mountpoint) {
|
||||
fatal_error(gettext("AppArmor does not appear to be started. Please enable AppArmor and try again."));
|
||||
}
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my $profiling = shift;
|
||||
|
||||
unless ($profiling) {
|
||||
$profiling = UI_GetString(gettext("Please enter the program to profile: "), "")
|
||||
|| exit 0;
|
||||
}
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unless ($fqdbin && -e $fqdbin) {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
fatal_error(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' in the other window in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
} else {
|
||||
fatal_error(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
check_qualifiers($fqdbin);
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
my $profilefilename = getprofilefilename($fqdbin);
|
||||
if (-e $profilefilename) {
|
||||
$helpers{$fqdbin} = getprofileflags($profilefilename) || "enforce";
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
$helpers{$fqdbin} = "enforce";
|
||||
}
|
||||
|
||||
if ($helpers{$fqdbin} eq "enforce") {
|
||||
complain($fqdbin);
|
||||
reload($fqdbin);
|
||||
}
|
||||
|
||||
# When reading from syslog, it is possible to hit the default kernel
|
||||
# printk ratelimit. This will result in audit entries getting skipped,
|
||||
# making profile generation inaccurate. When using genprof, disable
|
||||
# the printk ratelimit, and restore it on exit.
|
||||
my $ratelimit_sysctl = "/proc/sys/kernel/printk_ratelimit";
|
||||
my $ratelimit_saved = sysctl_read($ratelimit_sysctl);
|
||||
END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); }
|
||||
sysctl_write($ratelimit_sysctl, 0);
|
||||
|
||||
UI_Info(gettext("\nBefore you begin, you may wish to check if a\nprofile already exists for the application you\nwish to confine. See the following wiki page for\nmore information:\nhttps://gitlab.com/apparmor/apparmor/wikis/Profiles"));
|
||||
|
||||
UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied."));
|
||||
|
||||
my $syslog = 1;
|
||||
my $logmark = "";
|
||||
my $done_profiling = 0;
|
||||
|
||||
$syslog = 0 if (-e "/var/log/audit/audit.log");
|
||||
|
||||
while (not $done_profiling) {
|
||||
if ($syslog) {
|
||||
$logmark = `date | md5sum`;
|
||||
chomp $logmark;
|
||||
$logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
|
||||
system("$logger -p kern.warn 'GenProf: $logmark'");
|
||||
} else {
|
||||
$logmark = last_audit_entry_time();
|
||||
}
|
||||
eval {
|
||||
|
||||
my $q = {};
|
||||
$q->{headers} = [ gettext("Profiling"), $fqdbin ];
|
||||
$q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
|
||||
$q->{default} = "CMD_SCAN";
|
||||
|
||||
my ($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_SCAN") {
|
||||
|
||||
my $lp_ret = do_logprof_pass($logmark);
|
||||
|
||||
$done_profiling = 1 if $lp_ret eq "FINISHED";
|
||||
|
||||
} else {
|
||||
|
||||
$done_profiling = 1;
|
||||
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
if ($@ =~ /FINISHING/) {
|
||||
$done_profiling = 1;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $p (sort keys %helpers) {
|
||||
if ($helpers{$p} eq "enforce") {
|
||||
enforce($p);
|
||||
reload($p);
|
||||
}
|
||||
}
|
||||
|
||||
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode."));
|
||||
UI_Info(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttps://gitlab.com/apparmor/apparmor/wikis/Profiles\n"));
|
||||
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub last_audit_entry_time {
|
||||
local $_ = `tail -1 /var/log/audit/audit.log`;
|
||||
my $logmark;
|
||||
if (/^*msg\=audit\((\d+\.\d+\:\d+).*\).*$/) {
|
||||
$logmark = $1;
|
||||
} else {
|
||||
$logmark = "";
|
||||
}
|
||||
return $logmark;
|
||||
}
|
72
deprecated/utils/aa-logprof
Executable file
72
deprecated/utils/aa-logprof
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
setup_yast();
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $logmark;
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'logmark|m=s' => \$logmark,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
do_logprof_pass($logmark);
|
||||
|
||||
shutdown_yast();
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ -m \"mark in log to start processing after\""), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
821
deprecated/utils/aa-repo.pl
Normal file
821
deprecated/utils/aa-repo.pl
Normal file
@@ -0,0 +1,821 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2008 Dominic Reynolds. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
my $usage =
|
||||
"aa-repo.pl --command args\n";
|
||||
|
||||
my $usage_search =
|
||||
" --search [author=XXX] [prog=XXX] [id=XXX]
|
||||
Search the repository for profiles matching the search criteria
|
||||
and return the results.
|
||||
NOTE: One --search switch per option
|
||||
|
||||
--verbose|v
|
||||
Verbosity level. Supply either one or two switches. Two switches
|
||||
adds full profile text in returned search results.\n";
|
||||
|
||||
my $usage_push =
|
||||
|
||||
" --push [--profile=XXX|all] [--changelog=XXX]
|
||||
Push local profiles to repository, uses configured user and upon
|
||||
overwrite of an existing profile in the repository then prompt
|
||||
user with a diff for confirmation XXX the name of the application
|
||||
whose profile should be uploaded or \"all\" to upload all
|
||||
profiles. Multiple --profile switches may be passed to supply
|
||||
multiple profile names
|
||||
|
||||
e.g. --push --profile /usr/sbin/mdnsd --profile /usr/sbin/ftp
|
||||
e.g. --push --profile all\n";
|
||||
|
||||
my $usage_pull =
|
||||
" --pull [--author=XXX] [--profile=XXX] or [--id=XXX] [--mode=complain]
|
||||
pull remote profiles and install on local system
|
||||
If operation will change local profiles then prompt user with
|
||||
diff for confirmation
|
||||
NOTE: One --pull switch per option and there are three acceptable
|
||||
combinations
|
||||
|
||||
--pull --author=XXX
|
||||
* pull all profiles in the repo for the author
|
||||
|
||||
--pull --author=XXX --profile=XXXX
|
||||
* pull the profile for prog owned by author
|
||||
|
||||
--pull --id=XXXX
|
||||
* pull the profile with id
|
||||
|
||||
--pull --mode=complain
|
||||
* set the profile(s) to complain mode when installed
|
||||
|
||||
Profiles are checked for conflicts with currently installed
|
||||
profiles and presented as a list to the user to confirm and view.\n";
|
||||
|
||||
|
||||
my $usage_sync =
|
||||
" --sync [--up] [--down] [--noconfirm]
|
||||
Synchronize local profile set with the repository - showing
|
||||
changes and allowing prompting the user with the diffs and
|
||||
suggest the newest version to be activated. If the --all option
|
||||
is passed then treat profiles not marked as remote as new
|
||||
profiles that will be uploaded to the repository.\n";
|
||||
|
||||
my $usage_stat =
|
||||
" --status
|
||||
Show the current status of the local profile set. This operation
|
||||
is similar to sync but does not prompt the user to up|down load
|
||||
changes\n";
|
||||
|
||||
my $usage_getconfig =
|
||||
" --getconfig|c
|
||||
Print the current configuration for the repsository\n";
|
||||
|
||||
|
||||
my $usage_setconfig =
|
||||
" --setconfig [url=xxx] [username=xxxx] [password=xxxx] [enabled=(yes|no)]
|
||||
[upload=(yes|no)]
|
||||
Set the configuration options for the repository.
|
||||
NOTE: One --setconfig switch per option\n";
|
||||
|
||||
my $usage_bottom =
|
||||
" --quiet|q Don't prompt user - assume that all changes should be made.
|
||||
|
||||
ISSUES:
|
||||
o Should changes made to the system be recorded somehow? An audit event?
|
||||
o Should the tool allow a repo/distro to be passed for each operation?
|
||||
|
||||
";
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
use Immunix::Repository;
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $verbose = '';
|
||||
|
||||
my ( $id, $author, $mode, %search, $sync, $getconfig, $push,
|
||||
$pull, %setconfig, @profiles, $all, $changelog, $stat );
|
||||
|
||||
GetOptions(
|
||||
'search=s%' => \%search,
|
||||
'sync=s' => \$sync,
|
||||
'status' => \$stat,
|
||||
'getconfig|c' => \$getconfig,
|
||||
'setconfig=s%' => \%setconfig,
|
||||
'push' => \$push,
|
||||
'id=s' => \$id,
|
||||
'author=s' => \$author,
|
||||
'profile=s' => \@profiles,
|
||||
'changelog=s' => \$changelog,
|
||||
'pull' => \$pull,
|
||||
'all|a' => \$all,
|
||||
'help|h' => \$help,
|
||||
'verbose|v+' => \$verbose
|
||||
);
|
||||
|
||||
#
|
||||
# Root privs required to run the repo tool
|
||||
#
|
||||
if ( geteuid() != 0 ) {
|
||||
print STDERR gettext(
|
||||
"You must be logged in with root user privileges to use this program.\n"
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
# --help
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $config = get_repo_config();
|
||||
|
||||
#
|
||||
# --getconfig operation
|
||||
#
|
||||
&config && exit if $getconfig;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
unless ($sd_mountpoint) {
|
||||
fatal_error(gettext(
|
||||
"AppArmor does not appear to be started. Please enable AppArmor and try again."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#
|
||||
# --setconfig operation
|
||||
#
|
||||
if ( keys %setconfig ) {
|
||||
$config->{url} = $setconfig{url} if ( $setconfig{url} );
|
||||
$config->{distro} = $setconfig{distro} if ( $setconfig{distro} );
|
||||
$config->{enabled} = $setconfig{enabled} if ( $setconfig{enabled} );
|
||||
$config->{email} = $setconfig{email} if ( $setconfig{email} );
|
||||
$config->{user} = $setconfig{username} if ( $setconfig{username} );
|
||||
$config->{password} = $setconfig{password} if ( $setconfig{password} );
|
||||
$config->{upload} = $setconfig{upload} if ( $setconfig{upload} );
|
||||
set_repo_config( $config );
|
||||
}
|
||||
|
||||
#
|
||||
# --push operation
|
||||
#
|
||||
if ( $push ) {
|
||||
my ($conflicts, $repo_profiles, $local_profiles, @overrides);
|
||||
if ( ! @profiles ) {
|
||||
print STDERR gettext(
|
||||
"Must supply at least one profile using \"--profile XXX\" to --push\n"
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
print STDERR Data::Dumper->Dump([@profiles], [qw(*profiles)]);
|
||||
}
|
||||
my $changelog = $changelog?$changelog:"none";
|
||||
push_profiles( \@profiles, $changelog, 1 );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# --pull operation
|
||||
#
|
||||
if ( $pull ) {
|
||||
my $type = "";
|
||||
if ( $id ) {
|
||||
if ( $author || @profiles ) {
|
||||
print STDERR gettext(
|
||||
"Option --id=XX is only allowed by itself and not in combination to
|
||||
other options for the --pull command.\n"
|
||||
);
|
||||
exit 1;
|
||||
}
|
||||
$type = "id";
|
||||
}
|
||||
if ( @profiles && ! $author ) {
|
||||
print STDERR gettext(
|
||||
"Option --profile=XX requires that the --author=XX option be supplied
|
||||
to distinguish a specific profile.\n"
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$type = "profile";
|
||||
}
|
||||
|
||||
my $mode = $mode eq "complain"?1:0;
|
||||
pull_profiles( \@profiles, $type, $mode, 1 );
|
||||
}
|
||||
|
||||
#
|
||||
# --search operation
|
||||
#
|
||||
if ( keys %search ) {
|
||||
if ( $search{id} ) {
|
||||
my($status,$result) = fetch_profile_by_id( $config->{url},
|
||||
$search{id} );
|
||||
if ($status) {
|
||||
my $title = sprintf(gettext( "Profile ID %s\n"), $search{id});
|
||||
console_print_search_results( $title,
|
||||
"profile",
|
||||
{ $result->{name} => $result }
|
||||
);
|
||||
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{author} && $search{prog} ) {
|
||||
my($status,$result) =
|
||||
fetch_profiles_by_name_and_user( $config->{url},
|
||||
$config->{distro},
|
||||
$search{prog},
|
||||
$search{author}
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title =
|
||||
sprintf(gettext("Profiles matching user: %s and program: %s\n"),
|
||||
$search{author},
|
||||
$search{prog}
|
||||
);
|
||||
console_print_search_results( $title, "profile", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{author} ) {
|
||||
my($status,$result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$search{author}
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title = sprintf(gettext( "Profiles for %s\n"), $search{author});
|
||||
console_print_search_results( $title, "profile", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{prog} ) {
|
||||
my($status,$result) = fetch_profiles_by_name( $config->{url},
|
||||
$config->{distro},
|
||||
$search{prog},
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title = sprintf(gettext("Profiles matching program: %s\n"),
|
||||
$search{prog});
|
||||
console_print_search_results( $title, "user", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} else {
|
||||
print STDERR
|
||||
"Unsupported search criteria. Please specify at least one of
|
||||
author=XXX prog=XXX id=XXX\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $stat ) {
|
||||
my ( $local_profiles, $remote_profiles );
|
||||
my $msg =
|
||||
" The following profiles are stored in the repository but
|
||||
are not synchronized with the copy in the repository\n";
|
||||
|
||||
my ($status, $result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user}
|
||||
);
|
||||
if ( $status ) {
|
||||
$remote_profiles = $result;
|
||||
} else {
|
||||
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
|
||||
$result);
|
||||
exit;
|
||||
}
|
||||
|
||||
readprofiles();
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
my ($local_only,$unsynched,$synched,$conflicts) = ({}, {}, {});
|
||||
$unsynched = find_profile_conflicts($remote_profiles, $local_profiles);
|
||||
for my $p ( keys %$local_profiles ) {
|
||||
if ( ! $remote_profiles->{$p} ) {
|
||||
$local_only->{$p} = $local_profiles->{$p};
|
||||
}
|
||||
}
|
||||
|
||||
for my $p ( keys %$remote_profiles ) {
|
||||
$synched->{$p} =
|
||||
$remote_profiles->{$p}->{profile} if ( ! %$unsynched->{$p} );
|
||||
}
|
||||
UI_status($synched, $unsynched, $local_only);
|
||||
}
|
||||
|
||||
######################
|
||||
# Helper functions
|
||||
######################
|
||||
|
||||
#
|
||||
# Compare the local profile set with the remote profile set.
|
||||
# Return a list of the conflicting profiles as a list
|
||||
# { PROFILE_NAME => [LOCAL_PROFILE, REMOTE_PROFILE] ]
|
||||
#
|
||||
#
|
||||
# remote_profiles = repository profiles as returned by one of the
|
||||
# Immunix::Repository::fetch... functions
|
||||
# local_profiles = hash ref containing
|
||||
# { name => serialized local profile }
|
||||
#
|
||||
#
|
||||
|
||||
sub find_profile_conflicts ($$) {
|
||||
my ($remote_profiles,$local_profiles) = @_;
|
||||
my $conflicts = {};
|
||||
for my $p ( keys(%$local_profiles) ) {
|
||||
if ( $local_profiles->{$p} and $remote_profiles->{$p} ) {
|
||||
my $p_local = $local_profiles->{$p};
|
||||
my $p_remote = $remote_profiles->{$p}->{profile};
|
||||
chomp($p_local);
|
||||
chomp($p_remote);
|
||||
if ( $p_remote ne $p_local ) {
|
||||
$conflicts->{$p} = [ $p_local, $p_remote ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return( $conflicts );
|
||||
}
|
||||
|
||||
sub serialize_local_profiles ($) {
|
||||
my $profiles = shift;
|
||||
my $local_profiles = {};
|
||||
for my $p ( keys %$profiles ) {
|
||||
my $serialize_opts = {};
|
||||
$serialize_opts->{NO_FLAGS} = 1;
|
||||
my $p_local = serialize_profile( $profiles->{$p},
|
||||
$p,
|
||||
$serialize_opts );
|
||||
$local_profiles->{$p} = $p_local;
|
||||
}
|
||||
return $local_profiles;
|
||||
}
|
||||
|
||||
|
||||
sub console_print_search_results ($$$) {
|
||||
my ($title, $type,$result) = @_;
|
||||
open(PAGER, "| less") or die "Can't open pager";
|
||||
print PAGER $title;
|
||||
print PAGER "Found " . values(%$result) . " profiles \n";
|
||||
for my $p ( values(%$result) ) {
|
||||
if ( $verbose ) {
|
||||
if ( $type eq "user" ) {
|
||||
print PAGER " Author [ " . $p->{username} . " ]\n";
|
||||
} elsif ( $type eq "profile" ) {
|
||||
print PAGER " Name [ " . $p->{name} . " ]\n";
|
||||
}
|
||||
print PAGER " Created [ " . $p->{created_at} . " ]\n";
|
||||
print PAGER " Downloads [ " . $p->{downloaded_count} . " ]\n";
|
||||
print PAGER " ID [ " . $p->{id} . " ]\n";
|
||||
if ( $verbose > 1 ) {
|
||||
print PAGER " Profile [ \n" . $p->{profile} . " ]\n\n";
|
||||
} else {
|
||||
print PAGER "\n";
|
||||
}
|
||||
} else {
|
||||
my $data = $type eq "user"?$p->{username}:$p->{name};
|
||||
print PAGER " " . $data . "\n";
|
||||
}
|
||||
}
|
||||
close PAGER;
|
||||
}
|
||||
|
||||
sub UI_resolve_profile_conflicts {
|
||||
|
||||
my ($explanation, $conflict_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @conflicts = map { [ $_,
|
||||
$conflict_hash->{$_}->[0],
|
||||
$conflict_hash->{$_}->[1]
|
||||
] }
|
||||
keys %$conflict_hash;
|
||||
my @commits = [];
|
||||
my $title = "Profile conflicts";
|
||||
my %resolution = ();
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_OVERWRITE",
|
||||
"CMD_KEEP",
|
||||
"CMD_VIEW_CHANGES",
|
||||
"CMD_ABORT",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_OVERWRITE";
|
||||
$q->{options} = [ map { $_->[0] } @conflicts ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
|
||||
}
|
||||
if ( $ans eq "CMD_OVERWRITE") {
|
||||
$q->{options} =
|
||||
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
|
||||
$conflicts[$arg]->[0] . " O":
|
||||
$_ }
|
||||
@{$q->{options}}
|
||||
];
|
||||
$resolution{$conflicts[$arg]->[0]} = "O";
|
||||
}
|
||||
if ( $ans eq "CMD_KEEP") {
|
||||
$q->{options} =
|
||||
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
|
||||
$conflicts[$arg]->[0] . " K":
|
||||
$_ }
|
||||
@{$q->{options}}
|
||||
];
|
||||
$resolution{$conflicts[$arg]->[0]} = "K";
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @conflicts;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
if ($ans eq "CMD_CONTINUE") {
|
||||
my @results = ();
|
||||
for my $p ( keys %resolution ) {
|
||||
if ( $resolution{$p} eq "O" ) {
|
||||
push @results, $p;
|
||||
}
|
||||
}
|
||||
return @results;
|
||||
}
|
||||
}
|
||||
|
||||
sub UI_display_profiles {
|
||||
my ($explanation, $profile_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @profiles = map { [ $_, $profile_hash->{$_} ] } keys %$profile_hash;
|
||||
my $title = gettext("Profiles");
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_VIEW",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_CONTINUE";
|
||||
$q->{options} = [ map { $_->[0] } @profiles ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW") {
|
||||
my $pager = get_pager();
|
||||
open ( PAGER, "| $pager" ) or die "Can't open $pager";
|
||||
print PAGER gettext("Profile: ") . $profiles[$arg]->[0] . "\n";
|
||||
print PAGER $profiles[$arg]->[1];
|
||||
close PAGER;
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @profiles;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
return;
|
||||
}
|
||||
|
||||
sub UI_display_profile_conflicts {
|
||||
my ($explanation, $conflict_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @conflicts = map { [ $_,
|
||||
$conflict_hash->{$_}->[0],
|
||||
$conflict_hash->{$_}->[1]
|
||||
] }
|
||||
keys %$conflict_hash;
|
||||
my @commits = [];
|
||||
my $title = gettext("Profile conflicts");
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_VIEW_CHANGES",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_CONTINUE";
|
||||
$q->{options} = [ map { $_->[0] } @conflicts ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @conflicts;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
return;
|
||||
}
|
||||
|
||||
sub usage {
|
||||
if ( $help eq "push" ) {
|
||||
print STDERR $usage . $usage_push ."\n";
|
||||
} elsif ( $help eq "pull" ) {
|
||||
print STDERR $usage . $usage_pull ."\n";
|
||||
} elsif ( $help eq "sync" ) {
|
||||
print STDERR $usage . $usage_sync ."\n";
|
||||
} elsif ( $help eq "getconfig" ) {
|
||||
print STDERR $usage . $usage_getconfig ."\n";
|
||||
} elsif ( $help eq "setconfig" ) {
|
||||
print STDERR $usage . $usage_setconfig ."\n";
|
||||
} elsif ( $help eq "status" ) {
|
||||
print STDERR $usage . $usage_stat ."\n";
|
||||
} elsif ( $help eq "search" ) {
|
||||
print STDERR $usage . $usage_search ."\n";
|
||||
} else {
|
||||
open(PAGER, "| less") or die "Can't open pager";
|
||||
print PAGER $usage .
|
||||
$usage_search .
|
||||
$usage_push .
|
||||
$usage_pull .
|
||||
$usage_sync .
|
||||
$usage_stat .
|
||||
$usage_setconfig .
|
||||
$usage_getconfig .
|
||||
$usage_bottom . "\n";
|
||||
close PAGER;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# --getconfig helper function
|
||||
#
|
||||
sub config {
|
||||
my $configstr = gettext("Current config\n");
|
||||
my $config = get_repo_config();
|
||||
$configstr .= "\turl:\t\t$config->{url}\n";
|
||||
$configstr .= "\tdistro:\t\t$config->{distro}\n";
|
||||
$configstr .= "\tenabled:\t$config->{enabled}\n";
|
||||
$configstr .= "\temail:\t\t$config->{email}\n";
|
||||
$configstr .= "\tusername:\t$config->{user}\n";
|
||||
$configstr .= "\tpassword:\t$config->{password}\n";
|
||||
$configstr .= "\tupload:\t\t$config->{upload}\n";
|
||||
print STDERR $configstr . "\n";
|
||||
}
|
||||
|
||||
#
|
||||
# helper function to push profiles to the repository
|
||||
# used by --push and --sync options
|
||||
#
|
||||
sub push_profiles($$$) {
|
||||
my ( $p_ref, $changelog, $confirm ) = @_;
|
||||
my ( $conflicts, $remote_profiles, $local_profiles, @overrides );
|
||||
my @profiles = @$p_ref;
|
||||
|
||||
my $conflict_msg =
|
||||
" The following profile(s) selected for upload conflicts with a profile already
|
||||
stored in the repository for your account. Please choose whether to keep the
|
||||
current version or overwrite it.\n";
|
||||
$all = 0;
|
||||
|
||||
readprofiles();
|
||||
my ($status, $result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user}
|
||||
);
|
||||
if ( $status ) {
|
||||
$remote_profiles = $result;
|
||||
} else {
|
||||
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
|
||||
$result);
|
||||
exit;
|
||||
}
|
||||
|
||||
$all = 1 if ( grep(/^all$/, @profiles) );
|
||||
|
||||
if ( $all ) {
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
} else {
|
||||
my $local_sd = {};
|
||||
for my $p ( @profiles ) {
|
||||
if ( !$sd{$p} ) {
|
||||
print STDERR
|
||||
sprintf(gettext("Profile for [%s] does not exist\n"), $p);
|
||||
exit;
|
||||
}
|
||||
$local_sd->{$p} = $sd{$p};
|
||||
}
|
||||
$local_profiles = serialize_local_profiles( $local_sd );
|
||||
}
|
||||
|
||||
$conflicts = find_profile_conflicts($remote_profiles, $local_profiles);
|
||||
|
||||
if ( keys %$conflicts ) {
|
||||
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
|
||||
}
|
||||
|
||||
if ( $local_profiles ) {
|
||||
my @uploads;
|
||||
for my $p ( keys %$local_profiles ) {
|
||||
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
|
||||
print STDERR gettext("Uploading ") . $p . "... ";
|
||||
my ($status,$result) = upload_profile( $config->{url},
|
||||
$config->{user},
|
||||
$config->{password},
|
||||
$config->{distro},
|
||||
$p,
|
||||
$local_profiles->{$p},
|
||||
$changelog
|
||||
);
|
||||
print STDERR gettext("done") . "\n";
|
||||
}
|
||||
if ( $status ) {
|
||||
push @uploads, $p;
|
||||
} else {
|
||||
print STDERR gettext("Error uploading") . "$p: $result\n";
|
||||
}
|
||||
}
|
||||
if ( @uploads ) {
|
||||
#
|
||||
# Currently the upload API with the repository returns the
|
||||
# the current users profile set before the update so we have
|
||||
# to refetch to obtain the metadata to update the local profiles
|
||||
#
|
||||
my $repo_p = [];
|
||||
print STDERR gettext("Updating local profile metedata....\n");
|
||||
my ($status,$result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user} );
|
||||
if ( $status ) {
|
||||
for my $p ( @uploads ) {
|
||||
push( @$repo_p, [$p, $result->{$p}] ) if ( $result->{$p} );
|
||||
}
|
||||
activate_repo_profiles( $config->{url}, $repo_p, 0 );
|
||||
print STDERR gettext(" done\n");
|
||||
} else {
|
||||
print STDERR gettext(
|
||||
"Failed to retrieve updated profiles from the repository. Error: "
|
||||
) . $result . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Helper function for pulling profiles from the repository
|
||||
# used by --pull and --sync options
|
||||
#
|
||||
sub pull_profiles($$$$) {
|
||||
my ( $p_ref, $mode, $confirm, $opts ) = @_;
|
||||
my @profiles = @$p_ref;
|
||||
my ( $conflicts, $commit_list, $remote_profiles,
|
||||
$local_profiles, @overrides );
|
||||
|
||||
my $conflict_msg =
|
||||
" The following profiles selected for download conflict with profiles
|
||||
already deployed on the system. Please choose whether to keep the local
|
||||
version or overwrite with the version from the repository\n";
|
||||
|
||||
readprofiles();
|
||||
|
||||
if ( $opts->{id} ) {
|
||||
my ($status,$newp) = fetch_profile_by_id( $config->{url}, $opts->{id} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(
|
||||
sprintf("Error occured during operation\n\t[%s]\n",
|
||||
$newp
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles = { $newp->{name} => $newp->{profile} };
|
||||
}
|
||||
} elsif ( @profiles && $opts->{author} ) {
|
||||
$remote_profiles = {};
|
||||
for my $p ( @profiles ) {
|
||||
my ($status,$profiles) =
|
||||
fetch_profiles_by_name_and_user( $config->{url},
|
||||
$config->{distro},
|
||||
$p,
|
||||
$opts->{author} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(sprintf(
|
||||
"Error occured during operation\n\t[%s]\n",
|
||||
$profiles
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles->{$p} = $profiles->{$p};
|
||||
}
|
||||
}
|
||||
} elsif ( $opts->{author} ) {
|
||||
my ($status,$profiles) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$opts->{author} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(sprintf(
|
||||
"Error occured during operation\n\t[%s]\n",
|
||||
$profiles
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles = $profiles;
|
||||
}
|
||||
}
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
$conflicts = find_profile_conflicts( $remote_profiles, $local_profiles );
|
||||
if ( keys %$conflicts ) {
|
||||
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
|
||||
}
|
||||
for my $p ( keys %$remote_profiles ) {
|
||||
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
|
||||
$remote_profiles->{$p}->{username} = $opts->{author};
|
||||
push @$commit_list, [$p, $remote_profiles->{$p}];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $commit_list and @$commit_list ) {
|
||||
activate_repo_profiles( $config->{url}, $commit_list, $mode );
|
||||
system("rcapparmor reload");
|
||||
} else {
|
||||
UI_Info(gettext("No changes to make"));
|
||||
}
|
||||
}
|
||||
|
||||
sub UI_status {
|
||||
|
||||
my ($synched, $unsynched, $local) = @_;
|
||||
my $url = $config->{url};
|
||||
my $synched_text = gettext("Synchronized repository profiles:\t\t") .
|
||||
keys %$synched;
|
||||
my $unsynched_text = gettext("Unsynchronized repository profiles:\t") .
|
||||
keys %$unsynched;
|
||||
my $local_text = gettext("Local only profiles :\t\t\t") . keys %$local;
|
||||
my $options = [ $synched_text, $unsynched_text, $local_text ];
|
||||
my $title = gettext("Profile Status");
|
||||
my $explanation = gettext(
|
||||
" This is the current status of active profiles on the system.
|
||||
To view the profiles or unsyncronized changes select VIEW\n"
|
||||
);
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
$q->{explanation} = $explanation;
|
||||
$q->{functions} = [ "CMD_VIEW", "CMD_FINISHED", ];
|
||||
$q->{default} = "CMD_FINISHED";
|
||||
$q->{options} = $options;
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW") {
|
||||
if ( $arg == 0 ) {
|
||||
UI_display_profiles(
|
||||
gettext("Profiles stored in the repository"),
|
||||
$synched
|
||||
);
|
||||
} elsif ( $arg == 1 ) {
|
||||
UI_display_profile_conflicts(
|
||||
gettext("Unsyncronised profile changes"),
|
||||
$unsynched
|
||||
);
|
||||
} elsif ( $arg == 2 ) {
|
||||
UI_display_profiles(
|
||||
gettext("Profiles stored in the repository"),
|
||||
$local
|
||||
);
|
||||
}
|
||||
}
|
||||
} until $ans =~ /^CMD_FINSHED/;
|
||||
}
|
||||
|
||||
|
218
deprecated/utils/aa-status
Normal file
218
deprecated/utils/aa-status
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/perl -w
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2005-2006 Novell/SUSE
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $confdir = "/etc/apparmor";
|
||||
my $sd_mountpoint;
|
||||
my $check_enabled = 0;
|
||||
my $count_enforced = 0;
|
||||
my $count_profiled = 0;
|
||||
my $count_complain = 0;
|
||||
my $verbose = 0;
|
||||
my $help;
|
||||
|
||||
GetOptions(
|
||||
'complaining' => \$count_complain,
|
||||
'enabled' => \$check_enabled,
|
||||
'enforced' => \$count_enforced,
|
||||
'profiled' => \$count_profiled,
|
||||
'verbose|v' => \$verbose,
|
||||
'help|h' => \$help,
|
||||
) or usage();
|
||||
|
||||
sub usage {
|
||||
print "Usage: $0 [OPTIONS]\n";
|
||||
print "Displays various information about the currently loaded AppArmor policy.\n";
|
||||
print "OPTIONS (one only):\n";
|
||||
print " --enabled returns error code if subdomain not enabled\n";
|
||||
print " --profiled prints the number of loaded policies\n";
|
||||
print " --enforced prints the number of loaded enforcing policies\n";
|
||||
print " --complaining prints the number of loaded non-enforcing policies\n";
|
||||
print " --verbose (default) displays multiple data points about loaded policy set\n";
|
||||
print " --help this message\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$verbose = 1 if ($count_complain + $check_enabled + $count_enforced + $count_profiled == 0);
|
||||
usage() if $help or ($count_complain + $check_enabled + $count_enforced + $count_profiled + $verbose > 1);
|
||||
|
||||
sub is_subdomain_loaded() {
|
||||
return 1 if (-d "/sys/module/apparmor");
|
||||
if(open(MODULES, "/proc/modules")) {
|
||||
while(<MODULES>) {
|
||||
return 1 if m/^(subdomain|apparmor)\s+/;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub find_subdomainfs() {
|
||||
|
||||
my $sd_mountpoint;
|
||||
if(open(MOUNTS, "/proc/mounts")) {
|
||||
while(<MOUNTS>) {
|
||||
$sd_mountpoint = "$1/apparmor" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/apparmor";
|
||||
$sd_mountpoint = "$1/subdomain" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/subdomain";
|
||||
$sd_mountpoint = $1 if m/^\S+\s+(\S+)\s+subdomainfs\s/ && -e "$1";
|
||||
}
|
||||
close(MOUNTS);
|
||||
}
|
||||
|
||||
return $sd_mountpoint;
|
||||
}
|
||||
|
||||
sub get_profiles {
|
||||
my $mountpoint = shift;
|
||||
my %profiles = ();
|
||||
|
||||
if (open(PROFILES, "$mountpoint/profiles")) {
|
||||
while(<PROFILES>) {
|
||||
$profiles{$1} = $2 if m/^([^\(]+)\s+\((\w+)\)$/;
|
||||
}
|
||||
close(PROFILES);
|
||||
}
|
||||
return (%profiles);
|
||||
}
|
||||
|
||||
sub get_processes {
|
||||
my %profiles = @_;
|
||||
my %processes = ();
|
||||
if (opendir(PROC, "/proc")) {
|
||||
my $file;
|
||||
while (defined($file = readdir(PROC))) {
|
||||
if ($file =~ m/^\d+/) {
|
||||
if (open(CURRENT, "/proc/$file/attr/current")) {
|
||||
while (<CURRENT>) {
|
||||
if (m/^([^\(]+)\s+\((\w+)\)$/) {
|
||||
$processes{$file}{'profile'} = $1;
|
||||
$processes{$file}{'mode'} = $2;
|
||||
} elsif (grep(abs_path("/proc/$file/exe") eq $_ , keys(%profiles))) {
|
||||
# keep only unconfined processes that have a profile defined
|
||||
$processes{$file}{'profile'} = abs_path("/proc/$file/exe");
|
||||
$processes{$file}{'mode'} = 'unconfined';
|
||||
}
|
||||
}
|
||||
close(CURRENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(PROC);
|
||||
}
|
||||
return (%processes);
|
||||
}
|
||||
|
||||
my $is_loaded = is_subdomain_loaded();
|
||||
|
||||
if (!$is_loaded) {
|
||||
print STDERR "apparmor module is not loaded.\n" if $verbose;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print "apparmor module is loaded.\n" if $verbose;
|
||||
|
||||
$sd_mountpoint = find_subdomainfs();
|
||||
if (!$sd_mountpoint) {
|
||||
print STDERR "apparmor filesystem is not mounted.\n" if $verbose;
|
||||
exit 3;
|
||||
}
|
||||
|
||||
if (! -r "$sd_mountpoint/profiles") {
|
||||
print STDERR "You do not have enough privilege to read the profile set.\n" if $verbose;
|
||||
exit 4;
|
||||
}
|
||||
|
||||
#print "subdomainfs is at $sd_mountpoint.\n" if $verbose;
|
||||
|
||||
# processes is a hash table :
|
||||
# * keys : processes pid
|
||||
# * values : hash containing information about the running process:
|
||||
# * 'profile' : name of the profile applied to the running process
|
||||
# * 'mode' : mode of the profile applied to the running process
|
||||
my %processes = ();
|
||||
my %enforced_processes = ();
|
||||
my %complain_processes = ();
|
||||
my %unconfined_processes = ();
|
||||
|
||||
# profiles is a hash table :
|
||||
# * keys : profile name
|
||||
# * value : profile mode
|
||||
my %profiles;
|
||||
my @enforced_profiles = ();
|
||||
my @complain_profiles = ();
|
||||
|
||||
%profiles = get_profiles($sd_mountpoint);
|
||||
@enforced_profiles = grep { $profiles{$_} eq 'enforce' } keys %profiles;
|
||||
@complain_profiles = grep { $profiles{$_} eq 'complain' } keys %profiles;
|
||||
|
||||
# we consider the case where no profiles are loaded to be "disabled" as well
|
||||
my $rc = (keys(%profiles) == 0) ? 2 : 0;
|
||||
|
||||
if ($check_enabled) {
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_profiled) {
|
||||
print scalar(keys(%profiles)). "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_enforced) {
|
||||
print $#enforced_profiles + 1 . "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_complain) {
|
||||
print $#complain_profiles + 1 . "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
|
||||
if ($verbose) {
|
||||
print keys(%profiles) . " profiles are loaded.\n";
|
||||
print $#enforced_profiles + 1 . " profiles are in enforce mode.\n";
|
||||
for (sort(@enforced_profiles)) {
|
||||
print " " . $_ . "\n";
|
||||
}
|
||||
print $#complain_profiles + 1 . " profiles are in complain mode.\n";
|
||||
for (sort(@complain_profiles)) {
|
||||
print " " . $_ . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
%processes = get_processes(%profiles);
|
||||
if ($verbose) {
|
||||
for (keys(%processes)) {
|
||||
$enforced_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'enforce';
|
||||
$complain_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'complain';
|
||||
# some early code uses unconfined instead of unconfined.
|
||||
$unconfined_processes{$_} = $processes{$_} if $processes{$_}{'mode'} =~ /uncon(fi|strai)ned/;
|
||||
}
|
||||
print keys(%processes) . " processes have profiles defined.\n";
|
||||
print keys(%enforced_processes) . " processes are in enforce mode :\n";
|
||||
for (sort { $enforced_processes{$a}{'profile'} cmp $enforced_processes{$b}{'profile'} } keys(%enforced_processes)) {
|
||||
print " " . $enforced_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
print keys(%complain_processes) . " processes are in complain mode.\n";
|
||||
for (sort { $complain_processes{$a}{'profile'} cmp $complain_processes{$b}{'profile'} } keys(%complain_processes)) {
|
||||
print " " . $complain_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
print keys(%unconfined_processes) . " processes are unconfined but have a profile defined.\n";
|
||||
for (sort { $unconfined_processes{$a}{'profile'} cmp $unconfined_processes{$b}{'profile'} } keys(%unconfined_processes)) {
|
||||
print " " . $unconfined_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
}
|
||||
|
||||
exit $rc;
|
113
deprecated/utils/aa-unconfined
Executable file
113
deprecated/utils/aa-unconfined
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/perl -w
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# unconfined -
|
||||
# audit local system for processes listening on network connections
|
||||
# that are not currently running with a profile.
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $paranoid = '';
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'paranoid' => \$paranoid,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
sub usage {
|
||||
printf(gettext("Usage: %s [ --paranoid ]\n"), $0);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $subdomainfs = check_for_subdomain();
|
||||
|
||||
die gettext("AppArmor does not appear to be started. Please enable AppArmor and try again.") . "\n"
|
||||
unless $subdomainfs;
|
||||
|
||||
my @pids;
|
||||
if ($paranoid) {
|
||||
opendir(PROC, "/proc") or die gettext("Can't read /proc\n");
|
||||
@pids = grep { /^\d+$/ } readdir(PROC);
|
||||
closedir(PROC);
|
||||
} else {
|
||||
if (open(NETSTAT, "LANG=C /bin/netstat -nlp |")) {
|
||||
while (<NETSTAT>) {
|
||||
chomp;
|
||||
push @pids, $5
|
||||
if /^(tcp|udp)\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\s+)\s+(\d+)\/(\S+)/;
|
||||
}
|
||||
close(NETSTAT);
|
||||
}
|
||||
}
|
||||
|
||||
for my $pid (sort { $a <=> $b } @pids) {
|
||||
my $prog = readlink "/proc/$pid/exe" or next;
|
||||
my $attr;
|
||||
if (open(CURRENT, "/proc/$pid/attr/current")) {
|
||||
while (<CURRENT>) {
|
||||
chomp;
|
||||
$attr = $_ if (/^\// || /^null/);
|
||||
}
|
||||
close(CURRENT);
|
||||
}
|
||||
my $cmdline = `cat /proc/$pid/cmdline`;
|
||||
my $pname = (split(/\0/, $cmdline))[0];
|
||||
if ($pname =~ /\// && !($pname eq $prog)) {
|
||||
$pname = "($pname) ";
|
||||
} else {
|
||||
$pname = "";
|
||||
}
|
||||
if (not $attr) {
|
||||
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
|
||||
|
||||
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
|
||||
$cmdline =~ s/\0/ /g;
|
||||
$cmdline =~ s/\s+$//;
|
||||
chomp $cmdline;
|
||||
print "$pid $prog ($cmdline) " . gettext("not confined\n");
|
||||
} else {
|
||||
print "$pid $prog $pname" . gettext("not confined\n");
|
||||
}
|
||||
} else {
|
||||
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
|
||||
|
||||
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
|
||||
$cmdline =~ s/\0/ /g;
|
||||
$cmdline =~ s/\s+$//;
|
||||
chomp $cmdline;
|
||||
print "$pid $prog ($cmdline) " . gettext("confined by") . " '$attr'\n";
|
||||
} else {
|
||||
print "$pid $prog $pname" . gettext("confined by") . " '$attr'\n";
|
||||
}
|
||||
}
|
||||
}
|
135
deprecated/utils/convert-profile.pl
Executable file
135
deprecated/utils/convert-profile.pl
Executable file
@@ -0,0 +1,135 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
# Very simple script to try converting AppArmor profiles to the new
|
||||
# profile syntax as of April 2007.
|
||||
#
|
||||
# Copyright (C) 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
use FileHandle;
|
||||
use File::Temp;
|
||||
use Getopt::Std;
|
||||
use strict;
|
||||
|
||||
sub match($) {
|
||||
my ($str) = @_;
|
||||
my @fields;
|
||||
|
||||
@fields = ($str =~ /^(\s*)([@\/]\S*)(\s.*,)$/);
|
||||
if (!@fields) {
|
||||
@fields = ($str =~ /^(\s*")((?:[^"]|\\")*)("\s.*,)$/);
|
||||
}
|
||||
|
||||
return @fields;
|
||||
}
|
||||
|
||||
sub alterations($) {
|
||||
my ($str) = @_;
|
||||
|
||||
if ($str =~ /^([^{]*){([^}]*,[^}]*)}(.*)$/) {
|
||||
my @strs = map { "$1$_$3" } split(/,/, $2);
|
||||
return map { alterations($_) } @strs;
|
||||
} else {
|
||||
return ($str);
|
||||
}
|
||||
}
|
||||
|
||||
my %known_dirs;
|
||||
|
||||
sub remember_pathname($) {
|
||||
my ($str) = @_;
|
||||
my $pathname;
|
||||
|
||||
for (split /(\/)/, $str) {
|
||||
if ($_ eq '/' && $pathname ne '') {
|
||||
#print "<<>> $pathname\n";
|
||||
$known_dirs{$pathname} = 1;
|
||||
}
|
||||
$pathname .= $_;
|
||||
}
|
||||
}
|
||||
|
||||
sub add_slash($$) {
|
||||
my ($str, $perms) = @_;
|
||||
|
||||
return exists $known_dirs{$str} || -d $str;
|
||||
}
|
||||
|
||||
sub never_add_slash($$) {
|
||||
my ($str, $perms) = @_;
|
||||
|
||||
return $perms =~ /[lmx]/ || $str =~ /\.(so|cf|db|conf|config|log|pid|so\*)$/ ||
|
||||
$str =~ /(\*\*|\/)$/ || (-e $str && ! -d $str);
|
||||
|
||||
}
|
||||
|
||||
our($opt_i);
|
||||
getopts('i');
|
||||
|
||||
foreach my $filename (@ARGV) {
|
||||
my $fh_in;
|
||||
|
||||
$fh_in = new FileHandle("< $filename")
|
||||
or die "$filename: $!\n";
|
||||
|
||||
while (<$fh_in>) {
|
||||
if (my @fields = match($_)) {
|
||||
for my $x (alterations($fields[1])) {
|
||||
remember_pathname($x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (@ARGV == 0) {
|
||||
print "Usage: $0 profile ...\n";
|
||||
print "Tries to convert the profile to the new profile syntax, and\n" .
|
||||
"prints the result to standard output. The result may need" .
|
||||
"further review.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
foreach my $filename (@ARGV) {
|
||||
my ($fh_in, $fh_out, $tmpname);
|
||||
|
||||
$fh_in = new FileHandle("< $filename")
|
||||
or die "$filename: $!\n";
|
||||
|
||||
if ($opt_i) {
|
||||
($fh_out, $tmpname) = mkstemp("$filename.XXXXXX")
|
||||
or die "$!\n";
|
||||
*STDOUT = $fh_out;
|
||||
}
|
||||
|
||||
while (<$fh_in>) {
|
||||
if (my @fields = match($_)) {
|
||||
for my $x (alterations($fields[1])) {
|
||||
if (never_add_slash($x, $fields[2])) {
|
||||
print $_;
|
||||
} elsif (add_slash($x, $fields[2])) {
|
||||
print "$fields[0]$x/$fields[2] # (dir)\n";
|
||||
} else {
|
||||
print "$fields[0]$x/$fields[2] # (maybe-dir)\n";
|
||||
print $_;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ($opt_i) {
|
||||
rename $tmpname, $filename
|
||||
or die "$filename: $!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# vim: smartindent softtabstop=4 shiftwidth=4
|
201
deprecated/utils/repair_obsolete_profiles
Executable file
201
deprecated/utils/repair_obsolete_profiles
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/perl -wi
|
||||
# automatically repair apparmor profiles that have had their supporting
|
||||
# infrastructure refactored out from underneath them
|
||||
|
||||
# note -i in shebang line -- this program will modify in-place
|
||||
# profiles or #include chunks specified on the command line without
|
||||
# backups. Please make some yourself and inspect the changes made by
|
||||
# this tool to ensure they look correct.
|
||||
|
||||
# It'll try to fix up #include files (supplied by SUSE/Immunix) that have
|
||||
# moved; it will also inspect many #include files that exist solely
|
||||
# for netdomain rule separation, and either remove the #include line
|
||||
# from profiles/includes or suck in the contents of the specific file,
|
||||
# depending if there was any non-netdomain content.
|
||||
|
||||
# If you haven't modified any of the files listed in the @useless array,
|
||||
# you probably don't have to concern yourself with the complicated part
|
||||
# of the previous paragraph. If you did modify any of those files, this
|
||||
# tool will inspect those for changes, try to update any lines in those
|
||||
# files for correctness, and insert those lines directly into the
|
||||
# referencing profiles.
|
||||
|
||||
our %count_cache;
|
||||
|
||||
# count the number of 'interesting' lines in the file
|
||||
sub numlines ($) {
|
||||
my $name = $_[0];
|
||||
|
||||
return $count_cache{$name} if $count_cache{$name};
|
||||
|
||||
open FH, $name or return 1; # can't tell -> not empty
|
||||
|
||||
my $linecount=0;
|
||||
while(<FH>) {
|
||||
if (m/^[^#]*#include/) {
|
||||
$linecount++;
|
||||
} elsif (m/^\s*#/) {
|
||||
# just a comment, skip it
|
||||
} elsif (m/\s*tcp_/) {
|
||||
# netdomain rules are unenforced, skip it
|
||||
} elsif (m/\s*udp_/) {
|
||||
# netdomain rules are unenforced, skip it
|
||||
} elsif (m/\S+/) {
|
||||
$linecount++;
|
||||
}
|
||||
}
|
||||
close FH;
|
||||
|
||||
$count_cache{$name} = $linecount;
|
||||
|
||||
return $linecount;
|
||||
}
|
||||
|
||||
# given a single line from a profile, perform some search/replace
|
||||
# operations to reflect new locations for old files.
|
||||
#
|
||||
# change #include lines that reference files in the @useless array:
|
||||
# don't print the #include any more, and either suck in the contents of
|
||||
# the referenced file (calling itself recursively to fix up _those_
|
||||
# files) or just leave well enough alone, if the file had no
|
||||
# 'interesting' lines as defined above.
|
||||
|
||||
%transforms = (
|
||||
# renamed around SuSE 9.3
|
||||
"abstractions/kde3" => "abstractions/kde",
|
||||
"abstractions/user-GTK" => "abstractions/gnome",
|
||||
"abstractions/user-Xauthority" => "abstractions/X",
|
||||
|
||||
# user-custom -> program-chunks around SHASS 1.1, but these changed dirs
|
||||
"user-custom/fonts" => "abstractions/fonts",
|
||||
"user-custom/kde3" => "abstractions/kde",
|
||||
"user-custom/user-GTK" => "abstractions/gnome",
|
||||
"user-custom/user-mail" => "abstractions/user-mail",
|
||||
"user-custom/user-manpages" => "abstractions/user-manpages",
|
||||
"user-custom/user-Xauthority" => "abstractions/X",
|
||||
"user-custom/user-tmp" => "abstractions/user-tmp",
|
||||
|
||||
# try to forget the -files
|
||||
"program-chunks/base-files" => "abstractions/base",
|
||||
"program-chunks/nameservice-files" => "abstractions/nameservice",
|
||||
"immunix-standard/base-files" => "abstractions/base",
|
||||
"immunix-standard/nameservice-files" => "abstractions/nameservice",
|
||||
|
||||
# immunix-standard -> program-chunks
|
||||
"immunix-standard/postfix-bounce" => "program-chunks/postfix-bounce",
|
||||
"immunix-standard/postfix-cleanup" => "program-chunks/postfix-cleanup",
|
||||
"immunix-standard/postfix-common" => "program-chunks/postfix-common",
|
||||
"immunix-standard/postfix-flush" => "program-chunks/postfix-flush",
|
||||
"immunix-standard/postfix-local" => "program-chunks/postfix-local",
|
||||
"immunix-standard/postfix-master" => "program-chunks/postfix-master",
|
||||
"immunix-standard/postfix-nqmgr" => "program-chunks/postfix-nqmgr",
|
||||
"immunix-standard/postfix-pickup" => "program-chunks/postfix-pickup",
|
||||
"immunix-standard/postfix-proxymap" => "program-chunks/postfix-proxymap",
|
||||
"immunix-standard/postfix-qmgr" => "program-chunks/postfix-qmgr",
|
||||
"immunix-standard/postfix-showq" => "program-chunks/postfix-showq",
|
||||
"immunix-standard/postfix-smtp" => "program-chunks/postfix-smtp",
|
||||
"immunix-standard/postfix-smtpd" => "program-chunks/postfix-smtpd",
|
||||
"immunix-standard/postfix-trivial-rewrite" => "program-chunks/postfix-trivial-rewrite",
|
||||
"immunix-standard/apache-default-uri" => "program-chunks/apache-default-uri",
|
||||
"immunix-standard/at" => "program-chunks/at",
|
||||
);
|
||||
|
||||
# chunks that immunix tools never populated -- lets remove the ones that
|
||||
# don't have any useful information
|
||||
my @useless = qw{
|
||||
program-chunks/base-nd
|
||||
program-chunks/portmap-nd
|
||||
program-chunks/postfix-local-nd
|
||||
program-chunks/postfix-master-nd
|
||||
program-chunks/postfix-proxymap-nd
|
||||
program-chunks/postfix-smtpd-nd
|
||||
program-chunks/postfix-smtp-nd
|
||||
user-custom/base-nd
|
||||
user-custom/portmap-nd
|
||||
user-custom/postfix-local-nd
|
||||
user-custom/postfix-master-nd
|
||||
user-custom/postfix-proxymap-nd
|
||||
user-custom/postfix-smtpd-nd
|
||||
user-custom/postfix-smtp-nd
|
||||
immunix-standard/base-nd
|
||||
immunix-standard/portmap-nd
|
||||
immunix-standard/postfix-local-nd
|
||||
immunix-standard/postfix-master-nd
|
||||
immunix-standard/postfix-proxymap-nd
|
||||
immunix-standard/postfix-smtpd-nd
|
||||
immunix-standard/postfix-smtp-nd
|
||||
program-chunks/at
|
||||
program-chunks/fam
|
||||
program-chunks/httpd
|
||||
program-chunks/identd
|
||||
program-chunks/imapd
|
||||
program-chunks/ipop2d
|
||||
program-chunks/ipop3d
|
||||
program-chunks/lpd
|
||||
program-chunks/mutt
|
||||
program-chunks/named
|
||||
program-chunks/nmbd
|
||||
program-chunks/ntalkd
|
||||
program-chunks/ntpd
|
||||
program-chunks/postgres
|
||||
program-chunks/rpc.lockd
|
||||
program-chunks/rpc.nfsd
|
||||
program-chunks/rpc.statd
|
||||
program-chunks/samba
|
||||
program-chunks/sendmail.sendmail
|
||||
program-chunks/shells
|
||||
program-chunks/slocate
|
||||
program-chunks/snmpd
|
||||
program-chunks/spamc
|
||||
program-chunks/sshd
|
||||
program-chunks/swat
|
||||
program-chunks/syslogd
|
||||
program-chunks/talk
|
||||
program-chunks/xfs
|
||||
};
|
||||
|
||||
# create an alternation to speed up the regexp below
|
||||
my $useless = join('|', @useless);
|
||||
|
||||
sub fixup ($) {
|
||||
$line = $_[0];
|
||||
|
||||
$line =~ s/#include\s+<([^>]+)>/$i = (exists $transforms{$1}) ? $transforms{$1} : "$1"; "#include <$i>"/e;
|
||||
|
||||
if ($line =~ m/\s*#include\s+<($useless)>/) {
|
||||
my $file = $1;
|
||||
if (numlines("/etc/subdomain.d/$file") > 0) {
|
||||
my $succ = open INC, "/etc/subdomain.d/$file";
|
||||
if (not $succ) {
|
||||
print STDERR "Error opening /etc/subdomain.d/$file\n";
|
||||
} else {
|
||||
while(my $included_line = <INC>) {
|
||||
print fixup_loop($included_line);
|
||||
}
|
||||
close INC;
|
||||
}
|
||||
}
|
||||
$line = ""; # this line has been handled by the file
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
# call fixup on a single entry repeatedly -- this way, we can encode
|
||||
# 'small' changes in the fixup routine when they are made, rather than
|
||||
# encoding all possible starting points and which specific end point
|
||||
# they should go to.
|
||||
sub fixup_loop ($) {
|
||||
my $line = $_[0];
|
||||
my $saved;
|
||||
do {
|
||||
$saved = $line;
|
||||
$line = fixup($saved);
|
||||
} until ($line eq $saved);
|
||||
return $line;
|
||||
}
|
||||
|
||||
# main entry point; fix each line in every file in argv.
|
||||
while(<>) {
|
||||
print fixup_loop($_);
|
||||
}
|
Binary file not shown.
@@ -1,25 +0,0 @@
|
||||
The apparmor logo (logo-default-red.svg) was created by Noah Davis and
|
||||
released under the LGPL (licence included below).
|
||||
|
||||
Logo variants and uses:
|
||||
|
||||
logo-default-red.svg - default logo and coloration used for the apparmor
|
||||
project. Created for larger (64x64) uses.
|
||||
Not optimized for small 16x16 tiles.
|
||||
|
||||
|
||||
|
||||
License
|
||||
* Copyright (c) 2018 Noah Davis <noahadvs@gmail.com>
|
||||
*
|
||||
* The appaprmor logo is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
* COPYING.LGPL.
|
||||
*
|
||||
* This logo file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg height="64" width="64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#j" y1="54" y2="9"/><linearGradient id="b"><stop offset="0" stop-color="#bf4231"/><stop offset="1" stop-color="#e05e4c"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="32" x2="32" y1="58" y2="6"><stop offset="0" stop-color="#173f4f"/><stop offset="1" stop-color="#2f5361"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#b" y1="54" y2="9"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="20" x2="45" xlink:href="#k" y1="22" y2="47"/><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="37" x2="37" y1="46" y2="38"><stop offset="0" stop-color="#be4434"/><stop offset=".25" stop-color="#c44837"/><stop offset="1" stop-color="#cb4c3b"/></linearGradient><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="26" x2="50" xlink:href="#k" y1="16" y2="40"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="40" x2="47" xlink:href="#k" y1="38" y2="45"/><linearGradient id="i" gradientUnits="userSpaceOnUse" x1="43" x2="46" xlink:href="#k" y1="44" y2="47"/><linearGradient id="j"><stop offset="0" stop-color="#eff0f1"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><linearGradient id="k"><stop offset="0" stop-color="#292c2f"/><stop offset="1" stop-opacity="0"/></linearGradient><linearGradient id="l" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#j" y1="54" y2="9"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#b" y1="54" y2="9"/><path d="m32 6c-6.33333 3.35447-12.66667 4.72491-19 6v25.001953c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-25.001953c-6.33333-1.27509-12.66667-2.64553-19-6z" fill="url(#c)" stroke-linecap="square" stroke-width="2"/><path d="m13 36.001953v1c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-1c0 7-10.26331 16.561337-19 20.998047-8.73669-4.43671-19-13.998047-19-20.998047z" fill="#292c2f" opacity=".2" stroke-linecap="square" stroke-width="2"/><path d="m48 14-26.304688 32.304688 11.208985 11.208984c8.525508-4.614773 18.095703-13.751033 18.095703-20.511719v-20.001953z" fill="url(#i)" opacity=".2"/><path d="m40.824219 12.349609-17.617188 35.238282c2.735569 2.548653 5.806349 4.895376 8.792969 6.412109 7.392765-3.754157 16-12.076982 16-18v-22c-2.403402-.483885-4.789398-1.006952-7.175781-1.650391z" fill="url(#d)"/><path d="m32 9c-5.358808 2.838395-10.64102 3.921074-16 5v22c0 3.530034 3.17163 7.828219 7.207031 11.587891l17.617188-35.238282c-2.934573-.791246-5.868718-1.784199-8.824219-3.349609z" fill="url(#a)"/><path d="m24 14-8 16 20.935547 20.935547c1.522034-1.10756 3.001377-2.336903 4.361328-3.638672l-1.296875-1.296875-7-14z" fill="url(#e)" opacity=".2"/><path d="m28 14 12 32 8-16h-4z" fill="url(#g)" opacity=".2"/><g stroke-width="1.857143"><path d="m24 14 16 32 8-16h-4l-1 2h-6l-9-18zm14 20h4l-2 4z" fill="url(#l)"/><path d="m24 14-8 16h4l1-2h6l8.5 17.000001h4zm0 8 2 4h-4z" fill="url(#m)"/><path d="m32 38 4 8h4l-4-8z" fill="url(#f)"/></g><path d="m48 30-8 16 3.617188 3.617188c4.013144-3.887728 7.018045-8.222958 7.351562-11.9375.019301-.229864.03125-.456776.03125-.677735v-4.001953z" fill="url(#h)" opacity=".2"/></svg>
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@@ -1,605 +0,0 @@
|
||||
From 97b3200925ba627346432edf521d49de8bb018a3 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 4 Oct 2010 15:03:36 -0700
|
||||
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
|
||||
|
||||
Base support for network mediation.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/.gitignore | 1 +
|
||||
security/apparmor/Makefile | 42 ++++++++++-
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
security/apparmor/include/audit.h | 4 +
|
||||
security/apparmor/include/net.h | 59 +++++++++++++++
|
||||
security/apparmor/include/policy.h | 3 +
|
||||
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
|
||||
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 47 +++++++++++-
|
||||
10 files changed, 415 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/net.h
|
||||
create mode 100644 security/apparmor/net.c
|
||||
|
||||
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
|
||||
index 9cdec70d72b8..d5b291e94264 100644
|
||||
--- a/security/apparmor/.gitignore
|
||||
+++ b/security/apparmor/.gitignore
|
||||
@@ -1,5 +1,6 @@
|
||||
#
|
||||
# Generated include files
|
||||
#
|
||||
+net_names.h
|
||||
capability_names.h
|
||||
rlim_names.h
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index ad369a7aac24..a7dc10be232d 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
-clean-files := capability_names.h rlim_names.h
|
||||
+clean-files := capability_names.h rlim_names.h net_names.h
|
||||
|
||||
|
||||
# Build a lower case string table of capability names
|
||||
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
|
||||
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
+# Build a lower case string table of address family names
|
||||
+# Transform lines from
|
||||
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# [1] = "local",
|
||||
+# [2] = "inet",
|
||||
+#
|
||||
+# and build the securityfs entries for the mapping.
|
||||
+# Transforms lines from
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# #define AA_FS_AF_MASK "local inet"
|
||||
+quiet_cmd_make-af = GEN $@
|
||||
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
|
||||
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
|
||||
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@ ;\
|
||||
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
|
||||
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
|
||||
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
+
|
||||
+# Build a lower case string table of sock type names
|
||||
+# Transform lines from
|
||||
+# SOCK_STREAM = 1,
|
||||
+# to
|
||||
+# [1] = "stream",
|
||||
+quiet_cmd_make-sock = GEN $@
|
||||
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
|
||||
+ sed $^ >>$@ -r -n \
|
||||
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@
|
||||
|
||||
# Build a lower case string table of rlimit names.
|
||||
# Transforms lines from
|
||||
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
$(obj)/capability.o : $(obj)/capability_names.h
|
||||
+$(obj)/net.o : $(obj)/net_names.h
|
||||
$(obj)/resource.o : $(obj)/rlim_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(src)/Makefile
|
||||
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
|
||||
$(src)/Makefile
|
||||
$(call cmd,make-rlim)
|
||||
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
|
||||
+ $(srctree)/include/linux/net.h \
|
||||
+ $(src)/Makefile
|
||||
+ $(call cmd,make-af)
|
||||
+ $(call cmd,make-sock)
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 41073f70eb41..4d236736cfb8 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
+ AA_FS_DIR("network", aa_fs_entry_network),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index fdc4774318ba..0df708e8748b 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ int type, protocol;
|
||||
+ struct sock *sk;
|
||||
+ } net;
|
||||
};
|
||||
};
|
||||
|
||||
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
|
||||
new file mode 100644
|
||||
index 000000000000..55da1dad8720
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -0,0 +1,59 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation definitions.
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_NET_H
|
||||
+#define __AA_NET_H
|
||||
+
|
||||
+#include <net/sock.h>
|
||||
+
|
||||
+#include "apparmorfs.h"
|
||||
+
|
||||
+/* struct aa_net - network confinement data
|
||||
+ * @allowed: basic network families permissions
|
||||
+ * @audit_network: which network permissions to force audit
|
||||
+ * @quiet_network: which network permissions to quiet rejects
|
||||
+ */
|
||||
+struct aa_net {
|
||||
+ u16 allow[AF_MAX];
|
||||
+ u16 audit[AF_MAX];
|
||||
+ u16 quiet[AF_MAX];
|
||||
+};
|
||||
+
|
||||
+extern struct aa_fs_entry aa_fs_entry_network[];
|
||||
+
|
||||
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
|
||||
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
|
||||
+ .family = (F)}; \
|
||||
+ DEFINE_AUDIT_DATA(NAME, \
|
||||
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
|
||||
+ LSM_AUDIT_DATA_NONE, \
|
||||
+ OP); \
|
||||
+ NAME.u.net = &(NAME ## _net); \
|
||||
+ aad(&NAME)->net.type = (T); \
|
||||
+ aad(&NAME)->net.protocol = (P)
|
||||
+
|
||||
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
|
||||
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
|
||||
+ (SK)->sk_protocol)
|
||||
+
|
||||
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk);
|
||||
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
|
||||
+
|
||||
+static inline void aa_free_net_rules(struct aa_net *new)
|
||||
+{
|
||||
+ /* NOP */
|
||||
+}
|
||||
+
|
||||
+#endif /* __AA_NET_H */
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index 67bc96afe541..a3d18ea8d730 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "capability.h"
|
||||
#include "domain.h"
|
||||
#include "file.h"
|
||||
+#include "net.h"
|
||||
#include "lib.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -132,6 +133,7 @@ struct aa_data {
|
||||
* @policy: general match rules governing policy
|
||||
* @file: The set of rules governing basic file access and domain transitions
|
||||
* @caps: capabilities for the profile
|
||||
+ * @net: network controls for the profile
|
||||
* @rlimits: rlimits for the profile
|
||||
*
|
||||
* @dents: dentries for the profiles file entries in apparmorfs
|
||||
@@ -174,6 +176,7 @@ struct aa_profile {
|
||||
struct aa_policydb policy;
|
||||
struct aa_file_rules file;
|
||||
struct aa_caps caps;
|
||||
+ struct aa_net net;
|
||||
struct aa_rlimit rlimits;
|
||||
|
||||
struct aa_loaddata *rawdata;
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 709eacd23909..e3017129a404 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "include/context.h"
|
||||
#include "include/file.h"
|
||||
#include "include/ipc.h"
|
||||
+#include "include/net.h"
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
|
||||
+ NULL);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_bind(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_BIND, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_connect(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_CONNECT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_listen(struct socket *sock, int backlog)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_LISTEN, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_ACCEPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_sendmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SENDMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_recvmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size, int flags)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_RECVMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockname(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getpeername(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
|
||||
+}
|
||||
+
|
||||
static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
|
||||
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
|
||||
|
||||
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
|
||||
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
|
||||
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
|
||||
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
|
||||
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
|
||||
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
|
||||
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
|
||||
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
|
||||
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
|
||||
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
||||
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
||||
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
||||
+
|
||||
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
||||
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
||||
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
new file mode 100644
|
||||
index 000000000000..b9c8cd0e882e
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/net.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+#include "net_names.h"
|
||||
+
|
||||
+struct aa_fs_entry aa_fs_entry_network[] = {
|
||||
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+/* audit callback for net specific fields */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ audit_log_format(ab, " family=");
|
||||
+ if (address_family_names[sa->u.net->family]) {
|
||||
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
|
||||
+ }
|
||||
+ audit_log_format(ab, " sock_type=");
|
||||
+ if (sock_type_names[aad(sa)->net.type]) {
|
||||
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
|
||||
+ }
|
||||
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_net - audit network access
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @op: operation being checked
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ * @sk: socket auditing is being applied to
|
||||
+ * @error: error code for failure else 0
|
||||
+ *
|
||||
+ * Returns: %0 or sa->error else other errorcode on failure
|
||||
+ */
|
||||
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
+ int type, int protocol, struct sock *sk, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
|
||||
+
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ if (likely(!aad(&sa)->error)) {
|
||||
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
|
||||
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
|
||||
+ !(1 << aad(&sa)->net.type & audit_mask)))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
+ u16 kill_mask = 0;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+
|
||||
+ if (denied & kill_mask)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ if ((denied & quiet_mask) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
|
||||
+ }
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_net_perm - very course network access check
|
||||
+ * @op: operation being checked
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk)
|
||||
+{
|
||||
+ u16 family_mask;
|
||||
+ int error;
|
||||
+
|
||||
+ if ((family < 0) || (family >= AF_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((type < 0) || (type >= SOCK_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* unix domain and netlink sockets are handled by ipc */
|
||||
+ if (family == AF_UNIX || family == AF_NETLINK)
|
||||
+ return 0;
|
||||
+
|
||||
+ family_mask = profile->net.allow[family];
|
||||
+
|
||||
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
|
||||
+
|
||||
+ return audit_net(profile, op, family, type, protocol, sk, error);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_revalidate_sk - Revalidate access to a sock
|
||||
+ * @op: operation being checked
|
||||
+ * @sk: sock being revalidated (NOT NULL)
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_revalidate_sk(const char *op, struct sock *sk)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* aa_revalidate_sk should not be called from interrupt context
|
||||
+ * don't mediate these calls as they are not task related
|
||||
+ */
|
||||
+ if (in_interrupt())
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
|
||||
+ sk->sk_protocol, sk);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index def1fbd6bdfd..9fe7b9d4500f 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
|
||||
|
||||
aa_free_file_rules(&profile->file);
|
||||
aa_free_cap_rules(&profile->caps);
|
||||
+ aa_free_net_rules(&profile->net);
|
||||
aa_free_rlimit_rules(&profile->rlimits);
|
||||
|
||||
kzfree(profile->dirname);
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index 2e37c9c26bbd..bc23a5b3b113 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -217,6 +217,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
|
||||
+{
|
||||
+ if (unpack_nameX(e, AA_U16, name)) {
|
||||
+ if (!inbounds(e, sizeof(u16)))
|
||||
+ return 0;
|
||||
+ if (data)
|
||||
+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
|
||||
+ e->pos += sizeof(u16);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
|
||||
{
|
||||
if (unpack_nameX(e, AA_U32, name)) {
|
||||
@@ -519,7 +532,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
const char *tmpname, *tmpns = NULL, *name = NULL;
|
||||
- size_t ns_len;
|
||||
+ size_t ns_len, size = 0;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
struct aa_data *data;
|
||||
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (!unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
+ size = unpack_array(e, "net_allowed_af");
|
||||
+ if (size) {
|
||||
+
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ /* discard extraneous rules that this kernel will
|
||||
+ * never request
|
||||
+ */
|
||||
+ if (i >= AF_MAX) {
|
||||
+ u16 tmp;
|
||||
+ if (!unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ /*
|
||||
+ * allow unix domain and netlink sockets they are handled
|
||||
+ * by IPC
|
||||
+ */
|
||||
+ profile->net.allow[AF_UNIX] = 0xffff;
|
||||
+ profile->net.allow[AF_NETLINK] = 0xffff;
|
||||
+
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
profile->policy.dfa = unpack_dfa(e);
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,38 +0,0 @@
|
||||
From b866a43c2897f5469c9d787426144074a3713f6a Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 29 Jun 2012 17:34:00 -0700
|
||||
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
|
||||
mediation
|
||||
|
||||
If a profile specified a quieting of network denials for a given rule by
|
||||
either the quiet or deny rule qualifiers, the resultant quiet mask for
|
||||
denied requests was applied incorrectly, resulting in two potential bugs.
|
||||
1. The misapplied quiet mask would prevent denials from being correctly
|
||||
tested against the kill mask/mode. Thus network access requests that
|
||||
should have resulted in the application being killed did not.
|
||||
|
||||
2. The actual quieting of the denied network request was not being applied.
|
||||
This would result in network rejections always being logged even when
|
||||
they had been specifically marked as quieted.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/net.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
index b9c8cd0e882e..5ba19ad1d65c 100644
|
||||
--- a/security/apparmor/net.c
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
} else {
|
||||
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
u16 kill_mask = 0;
|
||||
- u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type);
|
||||
|
||||
if (denied & kill_mask)
|
||||
audit_type = AUDIT_APPARMOR_KILL;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,938 +0,0 @@
|
||||
From 4429c3f9522b608300cfe1ae148dc6cdadf3d76c Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 May 2012 10:58:05 -0700
|
||||
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
|
||||
|
||||
Add the ability for apparmor to do mediation of mount operations. Mount
|
||||
rules require an updated apparmor_parser (2.8 series) for policy compilation.
|
||||
|
||||
The basic form of the rules are.
|
||||
|
||||
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
|
||||
[audit] [deny] remount [conds]* [path],
|
||||
[audit] [deny] umount [conds]* [path],
|
||||
[audit] [deny] pivotroot [oldroot=<value>] <path>
|
||||
|
||||
remount is just a short cut for mount options=remount
|
||||
|
||||
where [conds] can be
|
||||
fstype=<expr>
|
||||
options=<expr>
|
||||
|
||||
Example mount commands
|
||||
mount, # allow all mounts, but not umount or pivotroot
|
||||
|
||||
mount fstype=procfs, # allow mounting procfs anywhere
|
||||
|
||||
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
|
||||
|
||||
mount /dev/sda -> /mnt,
|
||||
|
||||
mount /dev/sd** -> /mnt/**,
|
||||
|
||||
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
|
||||
|
||||
umount,
|
||||
|
||||
umount /m*,
|
||||
|
||||
See the apparmor userspace for full documentation
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Kees Cook <kees@ubuntu.com>
|
||||
---
|
||||
security/apparmor/Makefile | 2 +-
|
||||
security/apparmor/apparmorfs.c | 13 +
|
||||
security/apparmor/domain.c | 2 +-
|
||||
security/apparmor/include/apparmor.h | 3 +-
|
||||
security/apparmor/include/audit.h | 11 +
|
||||
security/apparmor/include/domain.h | 2 +
|
||||
security/apparmor/include/mount.h | 54 +++
|
||||
security/apparmor/lsm.c | 60 ++++
|
||||
security/apparmor/mount.c | 616 +++++++++++++++++++++++++++++++++++
|
||||
9 files changed, 760 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/mount.h
|
||||
create mode 100644 security/apparmor/mount.c
|
||||
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index a7dc10be232d..01368441f230 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o net.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o mount.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
clean-files := capability_names.h rlim_names.h net_names.h
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 4d236736cfb8..2e8d09e2368b 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
+static struct aa_fs_entry aa_fs_entry_mount[] = {
|
||||
+ AA_FS_FILE_STRING("mask", "mount umount"),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
|
||||
+ AA_FS_FILE_BOOLEAN("profile", 1),
|
||||
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
AA_FS_DIR("network", aa_fs_entry_network),
|
||||
+ AA_FS_DIR("mount", aa_fs_entry_mount),
|
||||
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index 001e133a3c8c..708b7e22b9b5 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
|
||||
*
|
||||
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
|
||||
*/
|
||||
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
{
|
||||
struct aa_profile *new_profile = NULL;
|
||||
struct aa_ns *ns = profile->ns;
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index 1750cc0721c1..3383dc66f30f 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -27,8 +27,9 @@
|
||||
#define AA_CLASS_NET 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
+#define AA_CLASS_MOUNT 7
|
||||
|
||||
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
|
||||
+#define AA_CLASS_LAST AA_CLASS_MOUNT
|
||||
|
||||
/* Control parameters settable through module/boot flags */
|
||||
extern enum audit_mode aa_g_audit;
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index 0df708e8748b..41374ad89547 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -70,6 +70,10 @@ enum audit_type {
|
||||
#define OP_FMMAP "file_mmap"
|
||||
#define OP_FMPROT "file_mprotect"
|
||||
|
||||
+#define OP_PIVOTROOT "pivotroot"
|
||||
+#define OP_MOUNT "mount"
|
||||
+#define OP_UMOUNT "umount"
|
||||
+
|
||||
#define OP_CREATE "create"
|
||||
#define OP_POST_CREATE "post_create"
|
||||
#define OP_BIND "bind"
|
||||
@@ -127,6 +131,13 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ const char *src_name;
|
||||
+ const char *type;
|
||||
+ const char *trans;
|
||||
+ const char *data;
|
||||
+ unsigned long flags;
|
||||
+ } mnt;
|
||||
struct {
|
||||
int type, protocol;
|
||||
struct sock *sk;
|
||||
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
|
||||
index 30544729878a..7bd21d20a2bd 100644
|
||||
--- a/security/apparmor/include/domain.h
|
||||
+++ b/security/apparmor/include/domain.h
|
||||
@@ -23,6 +23,8 @@ struct aa_domain {
|
||||
char **table;
|
||||
};
|
||||
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
|
||||
+
|
||||
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
|
||||
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
|
||||
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
|
||||
new file mode 100644
|
||||
index 000000000000..a43b1d62e428
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/mount.h
|
||||
@@ -0,0 +1,54 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor file mediation function definitions.
|
||||
+ *
|
||||
+ * Copyright 2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_MOUNT_H
|
||||
+#define __AA_MOUNT_H
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/path.h>
|
||||
+
|
||||
+#include "domain.h"
|
||||
+#include "policy.h"
|
||||
+
|
||||
+/* mount perms */
|
||||
+#define AA_MAY_PIVOTROOT 0x01
|
||||
+#define AA_MAY_MOUNT 0x02
|
||||
+#define AA_MAY_UMOUNT 0x04
|
||||
+#define AA_AUDIT_DATA 0x40
|
||||
+#define AA_CONT_MATCH 0x40
|
||||
+
|
||||
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data);
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name, unsigned long flags);
|
||||
+
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags);
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name);
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data);
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path);
|
||||
+
|
||||
+#endif /* __AA_MOUNT_H */
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index e3017129a404..ee58a2cca74f 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
#include "include/procattr.h"
|
||||
+#include "include/mount.h"
|
||||
|
||||
/* Flag indicating whether initialization completed */
|
||||
int apparmor_initialized __initdata;
|
||||
@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
|
||||
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
}
|
||||
|
||||
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
|
||||
+ const char *type, unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* Discard magic */
|
||||
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
|
||||
+ flags &= ~MS_MGC_MSK;
|
||||
+
|
||||
+ flags &= ~AA_MS_IGNORE_MASK;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile)) {
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ error = aa_remount(profile, path, flags, data);
|
||||
+ else if (flags & MS_BIND)
|
||||
+ error = aa_bind_mount(profile, path, dev_name, flags);
|
||||
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE))
|
||||
+ error = aa_mount_change_type(profile, path, flags);
|
||||
+ else if (flags & MS_MOVE)
|
||||
+ error = aa_move_mount(profile, path, dev_name);
|
||||
+ else
|
||||
+ error = aa_new_mount(profile, dev_name, path, type,
|
||||
+ flags, data);
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_umount(profile, mnt, flags);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_pivotroot(const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_pivotroot(profile, old_path, new_path);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(capget, apparmor_capget),
|
||||
LSM_HOOK_INIT(capable, apparmor_capable),
|
||||
|
||||
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
|
||||
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
|
||||
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
|
||||
+
|
||||
LSM_HOOK_INIT(path_link, apparmor_path_link),
|
||||
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
|
||||
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
|
||||
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
|
||||
new file mode 100644
|
||||
index 000000000000..9e95a41c015c
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/mount.c
|
||||
@@ -0,0 +1,616 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor mediation of files
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/mount.h>
|
||||
+#include <linux/namei.h>
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/domain.h"
|
||||
+#include "include/file.h"
|
||||
+#include "include/match.h"
|
||||
+#include "include/mount.h"
|
||||
+#include "include/path.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+
|
||||
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
|
||||
+{
|
||||
+ if (flags & MS_RDONLY)
|
||||
+ audit_log_format(ab, "ro");
|
||||
+ else
|
||||
+ audit_log_format(ab, "rw");
|
||||
+ if (flags & MS_NOSUID)
|
||||
+ audit_log_format(ab, ", nosuid");
|
||||
+ if (flags & MS_NODEV)
|
||||
+ audit_log_format(ab, ", nodev");
|
||||
+ if (flags & MS_NOEXEC)
|
||||
+ audit_log_format(ab, ", noexec");
|
||||
+ if (flags & MS_SYNCHRONOUS)
|
||||
+ audit_log_format(ab, ", sync");
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ audit_log_format(ab, ", remount");
|
||||
+ if (flags & MS_MANDLOCK)
|
||||
+ audit_log_format(ab, ", mand");
|
||||
+ if (flags & MS_DIRSYNC)
|
||||
+ audit_log_format(ab, ", dirsync");
|
||||
+ if (flags & MS_NOATIME)
|
||||
+ audit_log_format(ab, ", noatime");
|
||||
+ if (flags & MS_NODIRATIME)
|
||||
+ audit_log_format(ab, ", nodiratime");
|
||||
+ if (flags & MS_BIND)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
|
||||
+ if (flags & MS_MOVE)
|
||||
+ audit_log_format(ab, ", move");
|
||||
+ if (flags & MS_SILENT)
|
||||
+ audit_log_format(ab, ", silent");
|
||||
+ if (flags & MS_POSIXACL)
|
||||
+ audit_log_format(ab, ", acl");
|
||||
+ if (flags & MS_UNBINDABLE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
|
||||
+ ", unbindable");
|
||||
+ if (flags & MS_PRIVATE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
|
||||
+ ", private");
|
||||
+ if (flags & MS_SLAVE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
|
||||
+ ", slave");
|
||||
+ if (flags & MS_SHARED)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
|
||||
+ ", shared");
|
||||
+ if (flags & MS_RELATIME)
|
||||
+ audit_log_format(ab, ", relatime");
|
||||
+ if (flags & MS_I_VERSION)
|
||||
+ audit_log_format(ab, ", iversion");
|
||||
+ if (flags & MS_STRICTATIME)
|
||||
+ audit_log_format(ab, ", strictatime");
|
||||
+ if (flags & MS_NOUSER)
|
||||
+ audit_log_format(ab, ", nouser");
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_cb - call back for mount specific audit fields
|
||||
+ * @ab: audit_buffer (NOT NULL)
|
||||
+ * @va: audit struct to audit values of (NOT NULL)
|
||||
+ */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ if (aad(sa)->mnt.type) {
|
||||
+ audit_log_format(ab, " fstype=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.type);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.src_name) {
|
||||
+ audit_log_format(ab, " srcname=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.trans) {
|
||||
+ audit_log_format(ab, " trans=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.flags) {
|
||||
+ audit_log_format(ab, " flags=\"");
|
||||
+ audit_mnt_flags(ab, aad(sa)->mnt.flags);
|
||||
+ audit_log_format(ab, "\"");
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.data) {
|
||||
+ audit_log_format(ab, " options=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_mount - handle the auditing of mount operations
|
||||
+ * @profile: the profile being enforced (NOT NULL)
|
||||
+ * @gfp: allocation flags
|
||||
+ * @op: operation being mediated (NOT NULL)
|
||||
+ * @name: name of object being mediated (MAYBE NULL)
|
||||
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
|
||||
+ * @type: type of filesystem (MAYBE_NULL)
|
||||
+ * @trans: name of trans (MAYBE NULL)
|
||||
+ * @flags: filesystem idependent mount flags
|
||||
+ * @data: filesystem mount flags
|
||||
+ * @request: permissions requested
|
||||
+ * @perms: the permissions computed for the request (NOT NULL)
|
||||
+ * @info: extra information message (MAYBE NULL)
|
||||
+ * @error: 0 if operation allowed else failure error code
|
||||
+ *
|
||||
+ * Returns: %0 or error on failure
|
||||
+ */
|
||||
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
|
||||
+ const char *name, const char *src_name,
|
||||
+ const char *type, const char *trans,
|
||||
+ unsigned long flags, const void *data, u32 request,
|
||||
+ struct file_perms *perms, const char *info, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
|
||||
+
|
||||
+ if (likely(!error)) {
|
||||
+ u32 mask = perms->audit;
|
||||
+
|
||||
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
|
||||
+ mask = 0xffff;
|
||||
+
|
||||
+ /* mask off perms that are not being force audited */
|
||||
+ request &= mask;
|
||||
+
|
||||
+ if (likely(!request))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ /* only report permissions that were denied */
|
||||
+ request = request & ~perms->allow;
|
||||
+
|
||||
+ if (request & perms->kill)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ /* quiet known rejects, assumes quiet and kill do not overlap */
|
||||
+ if ((request & perms->quiet) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ request &= ~perms->quiet;
|
||||
+
|
||||
+ if (!request)
|
||||
+ return COMPLAIN_MODE(profile) ?
|
||||
+ complain_error(error) : error;
|
||||
+ }
|
||||
+
|
||||
+ aad(&sa)->name = name;
|
||||
+ aad(&sa)->mnt.src_name = src_name;
|
||||
+ aad(&sa)->mnt.type = type;
|
||||
+ aad(&sa)->mnt.trans = trans;
|
||||
+ aad(&sa)->mnt.flags = flags;
|
||||
+ if (data && (perms->audit & AA_AUDIT_DATA))
|
||||
+ aad(&sa)->mnt.data = data;
|
||||
+ aad(&sa)->info = info;
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt_flags - Do an ordered match on mount flags
|
||||
+ * @dfa: dfa to match against
|
||||
+ * @state: state to start in
|
||||
+ * @flags: mount flags to match against
|
||||
+ *
|
||||
+ * Mount flags are encoded as an ordered match. This is done instead of
|
||||
+ * checking against a simple bitmask, to allow for logical operations
|
||||
+ * on the flags.
|
||||
+ *
|
||||
+ * Returns: next state after flags match
|
||||
+ */
|
||||
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i <= 31 ; ++i) {
|
||||
+ if ((1 << i) & flags)
|
||||
+ state = aa_dfa_next(dfa, state, i + 1);
|
||||
+ }
|
||||
+
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * compute_mnt_perms - compute mount permission associated with @state
|
||||
+ * @dfa: dfa to match against (NOT NULL)
|
||||
+ * @state: state match finished in
|
||||
+ *
|
||||
+ * Returns: mount permissions
|
||||
+ */
|
||||
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
|
||||
+ unsigned int state)
|
||||
+{
|
||||
+ struct file_perms perms;
|
||||
+
|
||||
+ perms.kill = 0;
|
||||
+ perms.allow = dfa_user_allow(dfa, state);
|
||||
+ perms.audit = dfa_user_audit(dfa, state);
|
||||
+ perms.quiet = dfa_user_quiet(dfa, state);
|
||||
+ perms.xindex = dfa_user_xindex(dfa, state);
|
||||
+
|
||||
+ return perms;
|
||||
+}
|
||||
+
|
||||
+static const char *mnt_info_table[] = {
|
||||
+ "match succeeded",
|
||||
+ "failed mntpnt match",
|
||||
+ "failed srcname match",
|
||||
+ "failed type match",
|
||||
+ "failed flags match",
|
||||
+ "failed data match"
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Returns 0 on success else element that match failed in, this is the
|
||||
+ * index into the mnt_info_table above
|
||||
+ */
|
||||
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
|
||||
+ const char *mntpnt, const char *devname,
|
||||
+ const char *type, unsigned long flags,
|
||||
+ void *data, bool binary, struct file_perms *perms)
|
||||
+{
|
||||
+ unsigned int state;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, start, mntpnt);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (devname)
|
||||
+ state = aa_dfa_match(dfa, state, devname);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 2;
|
||||
+
|
||||
+ if (type)
|
||||
+ state = aa_dfa_match(dfa, state, type);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 3;
|
||||
+
|
||||
+ state = match_mnt_flags(dfa, state, flags);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* only match data if not binary and the DFA flags data is expected */
|
||||
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, state, data);
|
||||
+ if (!state)
|
||||
+ return 5;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* failed at end of flags match */
|
||||
+ return 4;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt - handle path matching for mount
|
||||
+ * @profile: the confining profile
|
||||
+ * @mntpnt: string for the mntpnt (NOT NULL)
|
||||
+ * @devname: string for the devname/src_name (MAYBE NULL)
|
||||
+ * @type: string for the dev type (MAYBE NULL)
|
||||
+ * @flags: mount flags to match
|
||||
+ * @data: fs mount data (MAYBE NULL)
|
||||
+ * @binary: whether @data is binary
|
||||
+ * @perms: Returns: permission found by the match
|
||||
+ * @info: Returns: infomation string about the match for logging
|
||||
+ *
|
||||
+ * Returns: 0 on success else error
|
||||
+ */
|
||||
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
|
||||
+ const char *devname, const char *type,
|
||||
+ unsigned long flags, void *data, bool binary,
|
||||
+ struct file_perms *perms, const char **info)
|
||||
+{
|
||||
+ int pos;
|
||||
+
|
||||
+ if (!profile->policy.dfa)
|
||||
+ return -EACCES;
|
||||
+
|
||||
+ pos = do_match_mnt(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ mntpnt, devname, type, flags, data, binary, perms);
|
||||
+ if (pos) {
|
||||
+ *info = mnt_info_table[pos];
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int path_flags(struct aa_profile *profile, const struct path *path)
|
||||
+{
|
||||
+ return profile->path_flags |
|
||||
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
|
||||
+}
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ const char *name, *info = NULL;
|
||||
+ char *buffer = NULL;
|
||||
+ int binary, error;
|
||||
+
|
||||
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *dev_name, unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ flags &= MS_REC | MS_BIND;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ /* These are the flags allowed by do_change_type() */
|
||||
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE);
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
|
||||
+ &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *orig_name)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!orig_name || !*orig_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *dev_buffer = NULL;
|
||||
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
|
||||
+ int binary = 1;
|
||||
+ int error;
|
||||
+
|
||||
+ dev_name = orig_dev_name;
|
||||
+ if (type) {
|
||||
+ int requires_dev;
|
||||
+ struct file_system_type *fstype = get_fs_type(type);
|
||||
+ if (!fstype)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
|
||||
+ put_filesystem(fstype);
|
||||
+
|
||||
+ if (requires_dev) {
|
||||
+ struct path dev_path;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name) {
|
||||
+ error = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&dev_path,
|
||||
+ path_flags(profile, &dev_path),
|
||||
+ &dev_buffer, &dev_name, &info);
|
||||
+ path_put(&dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
|
||||
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(dev_buffer);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ struct path path = { mnt, mnt->mnt_root };
|
||||
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (!error && profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_UMOUNT & ~perms.allow)
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
|
||||
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ struct aa_profile *target = NULL;
|
||||
+ char *old_buffer = NULL, *new_buffer = NULL;
|
||||
+ const char *old_name, *new_name = NULL, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ error = aa_path_name(old_path, path_flags(profile, old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(new_path, path_flags(profile, new_path),
|
||||
+ &new_buffer, &new_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ new_name);
|
||||
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
|
||||
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_PIVOTROOT & perms.allow) {
|
||||
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
|
||||
+ target = x_table_lookup(profile, perms.xindex);
|
||||
+ if (!target)
|
||||
+ error = -ENOENT;
|
||||
+ else
|
||||
+ error = aa_replace_current_profile(target);
|
||||
+ }
|
||||
+ } else
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
|
||||
+ old_name, NULL, target ? target->base.name : NULL,
|
||||
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
|
||||
+ aa_put_profile(target);
|
||||
+ kfree(old_buffer);
|
||||
+ kfree(new_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,605 +0,0 @@
|
||||
From adbeb027cbafd78a76d5786e082d7c7abb19a591 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 4 Oct 2010 15:03:36 -0700
|
||||
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
|
||||
|
||||
Base support for network mediation.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/.gitignore | 1 +
|
||||
security/apparmor/Makefile | 42 ++++++++++-
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
security/apparmor/include/audit.h | 4 +
|
||||
security/apparmor/include/net.h | 59 +++++++++++++++
|
||||
security/apparmor/include/policy.h | 3 +
|
||||
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
|
||||
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 47 +++++++++++-
|
||||
10 files changed, 415 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/net.h
|
||||
create mode 100644 security/apparmor/net.c
|
||||
|
||||
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
|
||||
index 9cdec70d72b8..d5b291e94264 100644
|
||||
--- a/security/apparmor/.gitignore
|
||||
+++ b/security/apparmor/.gitignore
|
||||
@@ -1,5 +1,6 @@
|
||||
#
|
||||
# Generated include files
|
||||
#
|
||||
+net_names.h
|
||||
capability_names.h
|
||||
rlim_names.h
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index ad369a7aac24..a7dc10be232d 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
-clean-files := capability_names.h rlim_names.h
|
||||
+clean-files := capability_names.h rlim_names.h net_names.h
|
||||
|
||||
|
||||
# Build a lower case string table of capability names
|
||||
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
|
||||
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
+# Build a lower case string table of address family names
|
||||
+# Transform lines from
|
||||
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# [1] = "local",
|
||||
+# [2] = "inet",
|
||||
+#
|
||||
+# and build the securityfs entries for the mapping.
|
||||
+# Transforms lines from
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# #define AA_FS_AF_MASK "local inet"
|
||||
+quiet_cmd_make-af = GEN $@
|
||||
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
|
||||
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
|
||||
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@ ;\
|
||||
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
|
||||
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
|
||||
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
+
|
||||
+# Build a lower case string table of sock type names
|
||||
+# Transform lines from
|
||||
+# SOCK_STREAM = 1,
|
||||
+# to
|
||||
+# [1] = "stream",
|
||||
+quiet_cmd_make-sock = GEN $@
|
||||
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
|
||||
+ sed $^ >>$@ -r -n \
|
||||
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@
|
||||
|
||||
# Build a lower case string table of rlimit names.
|
||||
# Transforms lines from
|
||||
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
$(obj)/capability.o : $(obj)/capability_names.h
|
||||
+$(obj)/net.o : $(obj)/net_names.h
|
||||
$(obj)/resource.o : $(obj)/rlim_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(src)/Makefile
|
||||
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
|
||||
$(src)/Makefile
|
||||
$(call cmd,make-rlim)
|
||||
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
|
||||
+ $(srctree)/include/linux/net.h \
|
||||
+ $(src)/Makefile
|
||||
+ $(call cmd,make-af)
|
||||
+ $(call cmd,make-sock)
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 4f6ac9dbc65d..4b121211e5e7 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
+ AA_FS_DIR("network", aa_fs_entry_network),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index fdc4774318ba..0df708e8748b 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ int type, protocol;
|
||||
+ struct sock *sk;
|
||||
+ } net;
|
||||
};
|
||||
};
|
||||
|
||||
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
|
||||
new file mode 100644
|
||||
index 000000000000..55da1dad8720
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -0,0 +1,59 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation definitions.
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_NET_H
|
||||
+#define __AA_NET_H
|
||||
+
|
||||
+#include <net/sock.h>
|
||||
+
|
||||
+#include "apparmorfs.h"
|
||||
+
|
||||
+/* struct aa_net - network confinement data
|
||||
+ * @allowed: basic network families permissions
|
||||
+ * @audit_network: which network permissions to force audit
|
||||
+ * @quiet_network: which network permissions to quiet rejects
|
||||
+ */
|
||||
+struct aa_net {
|
||||
+ u16 allow[AF_MAX];
|
||||
+ u16 audit[AF_MAX];
|
||||
+ u16 quiet[AF_MAX];
|
||||
+};
|
||||
+
|
||||
+extern struct aa_fs_entry aa_fs_entry_network[];
|
||||
+
|
||||
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
|
||||
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
|
||||
+ .family = (F)}; \
|
||||
+ DEFINE_AUDIT_DATA(NAME, \
|
||||
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
|
||||
+ LSM_AUDIT_DATA_NONE, \
|
||||
+ OP); \
|
||||
+ NAME.u.net = &(NAME ## _net); \
|
||||
+ aad(&NAME)->net.type = (T); \
|
||||
+ aad(&NAME)->net.protocol = (P)
|
||||
+
|
||||
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
|
||||
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
|
||||
+ (SK)->sk_protocol)
|
||||
+
|
||||
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk);
|
||||
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
|
||||
+
|
||||
+static inline void aa_free_net_rules(struct aa_net *new)
|
||||
+{
|
||||
+ /* NOP */
|
||||
+}
|
||||
+
|
||||
+#endif /* __AA_NET_H */
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index 67bc96afe541..a3d18ea8d730 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "capability.h"
|
||||
#include "domain.h"
|
||||
#include "file.h"
|
||||
+#include "net.h"
|
||||
#include "lib.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -132,6 +133,7 @@ struct aa_data {
|
||||
* @policy: general match rules governing policy
|
||||
* @file: The set of rules governing basic file access and domain transitions
|
||||
* @caps: capabilities for the profile
|
||||
+ * @net: network controls for the profile
|
||||
* @rlimits: rlimits for the profile
|
||||
*
|
||||
* @dents: dentries for the profiles file entries in apparmorfs
|
||||
@@ -174,6 +176,7 @@ struct aa_profile {
|
||||
struct aa_policydb policy;
|
||||
struct aa_file_rules file;
|
||||
struct aa_caps caps;
|
||||
+ struct aa_net net;
|
||||
struct aa_rlimit rlimits;
|
||||
|
||||
struct aa_loaddata *rawdata;
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 8f3c0f7aca5a..758ddf4a0791 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "include/context.h"
|
||||
#include "include/file.h"
|
||||
#include "include/ipc.h"
|
||||
+#include "include/net.h"
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
|
||||
+ NULL);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_bind(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_BIND, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_connect(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_CONNECT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_listen(struct socket *sock, int backlog)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_LISTEN, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_ACCEPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_sendmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SENDMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_recvmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size, int flags)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_RECVMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockname(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getpeername(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
|
||||
+}
|
||||
+
|
||||
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
|
||||
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
|
||||
|
||||
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
|
||||
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
|
||||
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
|
||||
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
|
||||
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
|
||||
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
|
||||
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
|
||||
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
|
||||
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
|
||||
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
||||
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
||||
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
||||
+
|
||||
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
||||
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
||||
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
new file mode 100644
|
||||
index 000000000000..b9c8cd0e882e
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/net.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+#include "net_names.h"
|
||||
+
|
||||
+struct aa_fs_entry aa_fs_entry_network[] = {
|
||||
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+/* audit callback for net specific fields */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ audit_log_format(ab, " family=");
|
||||
+ if (address_family_names[sa->u.net->family]) {
|
||||
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
|
||||
+ }
|
||||
+ audit_log_format(ab, " sock_type=");
|
||||
+ if (sock_type_names[aad(sa)->net.type]) {
|
||||
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
|
||||
+ }
|
||||
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_net - audit network access
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @op: operation being checked
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ * @sk: socket auditing is being applied to
|
||||
+ * @error: error code for failure else 0
|
||||
+ *
|
||||
+ * Returns: %0 or sa->error else other errorcode on failure
|
||||
+ */
|
||||
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
+ int type, int protocol, struct sock *sk, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
|
||||
+
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ if (likely(!aad(&sa)->error)) {
|
||||
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
|
||||
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
|
||||
+ !(1 << aad(&sa)->net.type & audit_mask)))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
+ u16 kill_mask = 0;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+
|
||||
+ if (denied & kill_mask)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ if ((denied & quiet_mask) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
|
||||
+ }
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_net_perm - very course network access check
|
||||
+ * @op: operation being checked
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk)
|
||||
+{
|
||||
+ u16 family_mask;
|
||||
+ int error;
|
||||
+
|
||||
+ if ((family < 0) || (family >= AF_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((type < 0) || (type >= SOCK_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* unix domain and netlink sockets are handled by ipc */
|
||||
+ if (family == AF_UNIX || family == AF_NETLINK)
|
||||
+ return 0;
|
||||
+
|
||||
+ family_mask = profile->net.allow[family];
|
||||
+
|
||||
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
|
||||
+
|
||||
+ return audit_net(profile, op, family, type, protocol, sk, error);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_revalidate_sk - Revalidate access to a sock
|
||||
+ * @op: operation being checked
|
||||
+ * @sk: sock being revalidated (NOT NULL)
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_revalidate_sk(const char *op, struct sock *sk)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* aa_revalidate_sk should not be called from interrupt context
|
||||
+ * don't mediate these calls as they are not task related
|
||||
+ */
|
||||
+ if (in_interrupt())
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
|
||||
+ sk->sk_protocol, sk);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index cf9d670dca94..0eea92aeb02d 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
|
||||
|
||||
aa_free_file_rules(&profile->file);
|
||||
aa_free_cap_rules(&profile->caps);
|
||||
+ aa_free_net_rules(&profile->net);
|
||||
aa_free_rlimit_rules(&profile->rlimits);
|
||||
|
||||
kzfree(profile->dirname);
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index f3422a91353c..89a1bd78f765 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -217,6 +217,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
|
||||
+{
|
||||
+ if (unpack_nameX(e, AA_U16, name)) {
|
||||
+ if (!inbounds(e, sizeof(u16)))
|
||||
+ return 0;
|
||||
+ if (data)
|
||||
+ *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
|
||||
+ e->pos += sizeof(u16);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
|
||||
{
|
||||
if (unpack_nameX(e, AA_U32, name)) {
|
||||
@@ -519,7 +532,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
const char *tmpname, *tmpns = NULL, *name = NULL;
|
||||
- size_t ns_len;
|
||||
+ size_t ns_len, size = 0;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
struct aa_data *data;
|
||||
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (!unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
+ size = unpack_array(e, "net_allowed_af");
|
||||
+ if (size) {
|
||||
+
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ /* discard extraneous rules that this kernel will
|
||||
+ * never request
|
||||
+ */
|
||||
+ if (i >= AF_MAX) {
|
||||
+ u16 tmp;
|
||||
+ if (!unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!unpack_u16(e, &profile->net.allow[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ /*
|
||||
+ * allow unix domain and netlink sockets they are handled
|
||||
+ * by IPC
|
||||
+ */
|
||||
+ profile->net.allow[AF_UNIX] = 0xffff;
|
||||
+ profile->net.allow[AF_NETLINK] = 0xffff;
|
||||
+
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
profile->policy.dfa = unpack_dfa(e);
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,38 +0,0 @@
|
||||
From 7ed04b256a6313a83a2d9c94f7295d81acf11848 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 29 Jun 2012 17:34:00 -0700
|
||||
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
|
||||
mediation
|
||||
|
||||
If a profile specified a quieting of network denials for a given rule by
|
||||
either the quiet or deny rule qualifiers, the resultant quiet mask for
|
||||
denied requests was applied incorrectly, resulting in two potential bugs.
|
||||
1. The misapplied quiet mask would prevent denials from being correctly
|
||||
tested against the kill mask/mode. Thus network access requests that
|
||||
should have resulted in the application being killed did not.
|
||||
|
||||
2. The actual quieting of the denied network request was not being applied.
|
||||
This would result in network rejections always being logged even when
|
||||
they had been specifically marked as quieted.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/net.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
index b9c8cd0e882e..5ba19ad1d65c 100644
|
||||
--- a/security/apparmor/net.c
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
} else {
|
||||
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
u16 kill_mask = 0;
|
||||
- u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type);
|
||||
|
||||
if (denied & kill_mask)
|
||||
audit_type = AUDIT_APPARMOR_KILL;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,938 +0,0 @@
|
||||
From 13765e11a34d38ce04b3c28f21fe94d420746a90 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 May 2012 10:58:05 -0700
|
||||
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
|
||||
|
||||
Add the ability for apparmor to do mediation of mount operations. Mount
|
||||
rules require an updated apparmor_parser (2.8 series) for policy compilation.
|
||||
|
||||
The basic form of the rules are.
|
||||
|
||||
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
|
||||
[audit] [deny] remount [conds]* [path],
|
||||
[audit] [deny] umount [conds]* [path],
|
||||
[audit] [deny] pivotroot [oldroot=<value>] <path>
|
||||
|
||||
remount is just a short cut for mount options=remount
|
||||
|
||||
where [conds] can be
|
||||
fstype=<expr>
|
||||
options=<expr>
|
||||
|
||||
Example mount commands
|
||||
mount, # allow all mounts, but not umount or pivotroot
|
||||
|
||||
mount fstype=procfs, # allow mounting procfs anywhere
|
||||
|
||||
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
|
||||
|
||||
mount /dev/sda -> /mnt,
|
||||
|
||||
mount /dev/sd** -> /mnt/**,
|
||||
|
||||
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
|
||||
|
||||
umount,
|
||||
|
||||
umount /m*,
|
||||
|
||||
See the apparmor userspace for full documentation
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Kees Cook <kees@ubuntu.com>
|
||||
---
|
||||
security/apparmor/Makefile | 2 +-
|
||||
security/apparmor/apparmorfs.c | 13 +
|
||||
security/apparmor/domain.c | 2 +-
|
||||
security/apparmor/include/apparmor.h | 3 +-
|
||||
security/apparmor/include/audit.h | 11 +
|
||||
security/apparmor/include/domain.h | 2 +
|
||||
security/apparmor/include/mount.h | 54 +++
|
||||
security/apparmor/lsm.c | 60 ++++
|
||||
security/apparmor/mount.c | 616 +++++++++++++++++++++++++++++++++++
|
||||
9 files changed, 760 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/mount.h
|
||||
create mode 100644 security/apparmor/mount.c
|
||||
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index a7dc10be232d..01368441f230 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o net.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o mount.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
clean-files := capability_names.h rlim_names.h net_names.h
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 4b121211e5e7..8e1c18b23d75 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
+static struct aa_fs_entry aa_fs_entry_mount[] = {
|
||||
+ AA_FS_FILE_STRING("mask", "mount umount"),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
|
||||
+ AA_FS_FILE_BOOLEAN("profile", 1),
|
||||
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
AA_FS_DIR("network", aa_fs_entry_network),
|
||||
+ AA_FS_DIR("mount", aa_fs_entry_mount),
|
||||
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index 001e133a3c8c..708b7e22b9b5 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
|
||||
*
|
||||
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
|
||||
*/
|
||||
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
{
|
||||
struct aa_profile *new_profile = NULL;
|
||||
struct aa_ns *ns = profile->ns;
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index 1750cc0721c1..3383dc66f30f 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -27,8 +27,9 @@
|
||||
#define AA_CLASS_NET 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
+#define AA_CLASS_MOUNT 7
|
||||
|
||||
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
|
||||
+#define AA_CLASS_LAST AA_CLASS_MOUNT
|
||||
|
||||
/* Control parameters settable through module/boot flags */
|
||||
extern enum audit_mode aa_g_audit;
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index 0df708e8748b..41374ad89547 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -70,6 +70,10 @@ enum audit_type {
|
||||
#define OP_FMMAP "file_mmap"
|
||||
#define OP_FMPROT "file_mprotect"
|
||||
|
||||
+#define OP_PIVOTROOT "pivotroot"
|
||||
+#define OP_MOUNT "mount"
|
||||
+#define OP_UMOUNT "umount"
|
||||
+
|
||||
#define OP_CREATE "create"
|
||||
#define OP_POST_CREATE "post_create"
|
||||
#define OP_BIND "bind"
|
||||
@@ -127,6 +131,13 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ const char *src_name;
|
||||
+ const char *type;
|
||||
+ const char *trans;
|
||||
+ const char *data;
|
||||
+ unsigned long flags;
|
||||
+ } mnt;
|
||||
struct {
|
||||
int type, protocol;
|
||||
struct sock *sk;
|
||||
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
|
||||
index 30544729878a..7bd21d20a2bd 100644
|
||||
--- a/security/apparmor/include/domain.h
|
||||
+++ b/security/apparmor/include/domain.h
|
||||
@@ -23,6 +23,8 @@ struct aa_domain {
|
||||
char **table;
|
||||
};
|
||||
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
|
||||
+
|
||||
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
|
||||
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
|
||||
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
|
||||
new file mode 100644
|
||||
index 000000000000..a43b1d62e428
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/mount.h
|
||||
@@ -0,0 +1,54 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor file mediation function definitions.
|
||||
+ *
|
||||
+ * Copyright 2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_MOUNT_H
|
||||
+#define __AA_MOUNT_H
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/path.h>
|
||||
+
|
||||
+#include "domain.h"
|
||||
+#include "policy.h"
|
||||
+
|
||||
+/* mount perms */
|
||||
+#define AA_MAY_PIVOTROOT 0x01
|
||||
+#define AA_MAY_MOUNT 0x02
|
||||
+#define AA_MAY_UMOUNT 0x04
|
||||
+#define AA_AUDIT_DATA 0x40
|
||||
+#define AA_CONT_MATCH 0x40
|
||||
+
|
||||
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data);
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name, unsigned long flags);
|
||||
+
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags);
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name);
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data);
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path);
|
||||
+
|
||||
+#endif /* __AA_MOUNT_H */
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 758ddf4a0791..b57f24045c0d 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
#include "include/procattr.h"
|
||||
+#include "include/mount.h"
|
||||
|
||||
/* Flag indicating whether initialization completed */
|
||||
int apparmor_initialized;
|
||||
@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
|
||||
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
}
|
||||
|
||||
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
|
||||
+ const char *type, unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* Discard magic */
|
||||
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
|
||||
+ flags &= ~MS_MGC_MSK;
|
||||
+
|
||||
+ flags &= ~AA_MS_IGNORE_MASK;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile)) {
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ error = aa_remount(profile, path, flags, data);
|
||||
+ else if (flags & MS_BIND)
|
||||
+ error = aa_bind_mount(profile, path, dev_name, flags);
|
||||
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE))
|
||||
+ error = aa_mount_change_type(profile, path, flags);
|
||||
+ else if (flags & MS_MOVE)
|
||||
+ error = aa_move_mount(profile, path, dev_name);
|
||||
+ else
|
||||
+ error = aa_new_mount(profile, dev_name, path, type,
|
||||
+ flags, data);
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_umount(profile, mnt, flags);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_pivotroot(const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_pivotroot(profile, old_path, new_path);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(capget, apparmor_capget),
|
||||
LSM_HOOK_INIT(capable, apparmor_capable),
|
||||
|
||||
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
|
||||
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
|
||||
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
|
||||
+
|
||||
LSM_HOOK_INIT(path_link, apparmor_path_link),
|
||||
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
|
||||
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
|
||||
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
|
||||
new file mode 100644
|
||||
index 000000000000..9e95a41c015c
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/mount.c
|
||||
@@ -0,0 +1,616 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor mediation of files
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/mount.h>
|
||||
+#include <linux/namei.h>
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/domain.h"
|
||||
+#include "include/file.h"
|
||||
+#include "include/match.h"
|
||||
+#include "include/mount.h"
|
||||
+#include "include/path.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+
|
||||
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
|
||||
+{
|
||||
+ if (flags & MS_RDONLY)
|
||||
+ audit_log_format(ab, "ro");
|
||||
+ else
|
||||
+ audit_log_format(ab, "rw");
|
||||
+ if (flags & MS_NOSUID)
|
||||
+ audit_log_format(ab, ", nosuid");
|
||||
+ if (flags & MS_NODEV)
|
||||
+ audit_log_format(ab, ", nodev");
|
||||
+ if (flags & MS_NOEXEC)
|
||||
+ audit_log_format(ab, ", noexec");
|
||||
+ if (flags & MS_SYNCHRONOUS)
|
||||
+ audit_log_format(ab, ", sync");
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ audit_log_format(ab, ", remount");
|
||||
+ if (flags & MS_MANDLOCK)
|
||||
+ audit_log_format(ab, ", mand");
|
||||
+ if (flags & MS_DIRSYNC)
|
||||
+ audit_log_format(ab, ", dirsync");
|
||||
+ if (flags & MS_NOATIME)
|
||||
+ audit_log_format(ab, ", noatime");
|
||||
+ if (flags & MS_NODIRATIME)
|
||||
+ audit_log_format(ab, ", nodiratime");
|
||||
+ if (flags & MS_BIND)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
|
||||
+ if (flags & MS_MOVE)
|
||||
+ audit_log_format(ab, ", move");
|
||||
+ if (flags & MS_SILENT)
|
||||
+ audit_log_format(ab, ", silent");
|
||||
+ if (flags & MS_POSIXACL)
|
||||
+ audit_log_format(ab, ", acl");
|
||||
+ if (flags & MS_UNBINDABLE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
|
||||
+ ", unbindable");
|
||||
+ if (flags & MS_PRIVATE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
|
||||
+ ", private");
|
||||
+ if (flags & MS_SLAVE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
|
||||
+ ", slave");
|
||||
+ if (flags & MS_SHARED)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
|
||||
+ ", shared");
|
||||
+ if (flags & MS_RELATIME)
|
||||
+ audit_log_format(ab, ", relatime");
|
||||
+ if (flags & MS_I_VERSION)
|
||||
+ audit_log_format(ab, ", iversion");
|
||||
+ if (flags & MS_STRICTATIME)
|
||||
+ audit_log_format(ab, ", strictatime");
|
||||
+ if (flags & MS_NOUSER)
|
||||
+ audit_log_format(ab, ", nouser");
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_cb - call back for mount specific audit fields
|
||||
+ * @ab: audit_buffer (NOT NULL)
|
||||
+ * @va: audit struct to audit values of (NOT NULL)
|
||||
+ */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ if (aad(sa)->mnt.type) {
|
||||
+ audit_log_format(ab, " fstype=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.type);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.src_name) {
|
||||
+ audit_log_format(ab, " srcname=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.trans) {
|
||||
+ audit_log_format(ab, " trans=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.flags) {
|
||||
+ audit_log_format(ab, " flags=\"");
|
||||
+ audit_mnt_flags(ab, aad(sa)->mnt.flags);
|
||||
+ audit_log_format(ab, "\"");
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.data) {
|
||||
+ audit_log_format(ab, " options=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_mount - handle the auditing of mount operations
|
||||
+ * @profile: the profile being enforced (NOT NULL)
|
||||
+ * @gfp: allocation flags
|
||||
+ * @op: operation being mediated (NOT NULL)
|
||||
+ * @name: name of object being mediated (MAYBE NULL)
|
||||
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
|
||||
+ * @type: type of filesystem (MAYBE_NULL)
|
||||
+ * @trans: name of trans (MAYBE NULL)
|
||||
+ * @flags: filesystem idependent mount flags
|
||||
+ * @data: filesystem mount flags
|
||||
+ * @request: permissions requested
|
||||
+ * @perms: the permissions computed for the request (NOT NULL)
|
||||
+ * @info: extra information message (MAYBE NULL)
|
||||
+ * @error: 0 if operation allowed else failure error code
|
||||
+ *
|
||||
+ * Returns: %0 or error on failure
|
||||
+ */
|
||||
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
|
||||
+ const char *name, const char *src_name,
|
||||
+ const char *type, const char *trans,
|
||||
+ unsigned long flags, const void *data, u32 request,
|
||||
+ struct file_perms *perms, const char *info, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
|
||||
+
|
||||
+ if (likely(!error)) {
|
||||
+ u32 mask = perms->audit;
|
||||
+
|
||||
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
|
||||
+ mask = 0xffff;
|
||||
+
|
||||
+ /* mask off perms that are not being force audited */
|
||||
+ request &= mask;
|
||||
+
|
||||
+ if (likely(!request))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ /* only report permissions that were denied */
|
||||
+ request = request & ~perms->allow;
|
||||
+
|
||||
+ if (request & perms->kill)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ /* quiet known rejects, assumes quiet and kill do not overlap */
|
||||
+ if ((request & perms->quiet) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ request &= ~perms->quiet;
|
||||
+
|
||||
+ if (!request)
|
||||
+ return COMPLAIN_MODE(profile) ?
|
||||
+ complain_error(error) : error;
|
||||
+ }
|
||||
+
|
||||
+ aad(&sa)->name = name;
|
||||
+ aad(&sa)->mnt.src_name = src_name;
|
||||
+ aad(&sa)->mnt.type = type;
|
||||
+ aad(&sa)->mnt.trans = trans;
|
||||
+ aad(&sa)->mnt.flags = flags;
|
||||
+ if (data && (perms->audit & AA_AUDIT_DATA))
|
||||
+ aad(&sa)->mnt.data = data;
|
||||
+ aad(&sa)->info = info;
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt_flags - Do an ordered match on mount flags
|
||||
+ * @dfa: dfa to match against
|
||||
+ * @state: state to start in
|
||||
+ * @flags: mount flags to match against
|
||||
+ *
|
||||
+ * Mount flags are encoded as an ordered match. This is done instead of
|
||||
+ * checking against a simple bitmask, to allow for logical operations
|
||||
+ * on the flags.
|
||||
+ *
|
||||
+ * Returns: next state after flags match
|
||||
+ */
|
||||
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i <= 31 ; ++i) {
|
||||
+ if ((1 << i) & flags)
|
||||
+ state = aa_dfa_next(dfa, state, i + 1);
|
||||
+ }
|
||||
+
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * compute_mnt_perms - compute mount permission associated with @state
|
||||
+ * @dfa: dfa to match against (NOT NULL)
|
||||
+ * @state: state match finished in
|
||||
+ *
|
||||
+ * Returns: mount permissions
|
||||
+ */
|
||||
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
|
||||
+ unsigned int state)
|
||||
+{
|
||||
+ struct file_perms perms;
|
||||
+
|
||||
+ perms.kill = 0;
|
||||
+ perms.allow = dfa_user_allow(dfa, state);
|
||||
+ perms.audit = dfa_user_audit(dfa, state);
|
||||
+ perms.quiet = dfa_user_quiet(dfa, state);
|
||||
+ perms.xindex = dfa_user_xindex(dfa, state);
|
||||
+
|
||||
+ return perms;
|
||||
+}
|
||||
+
|
||||
+static const char *mnt_info_table[] = {
|
||||
+ "match succeeded",
|
||||
+ "failed mntpnt match",
|
||||
+ "failed srcname match",
|
||||
+ "failed type match",
|
||||
+ "failed flags match",
|
||||
+ "failed data match"
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Returns 0 on success else element that match failed in, this is the
|
||||
+ * index into the mnt_info_table above
|
||||
+ */
|
||||
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
|
||||
+ const char *mntpnt, const char *devname,
|
||||
+ const char *type, unsigned long flags,
|
||||
+ void *data, bool binary, struct file_perms *perms)
|
||||
+{
|
||||
+ unsigned int state;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, start, mntpnt);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (devname)
|
||||
+ state = aa_dfa_match(dfa, state, devname);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 2;
|
||||
+
|
||||
+ if (type)
|
||||
+ state = aa_dfa_match(dfa, state, type);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 3;
|
||||
+
|
||||
+ state = match_mnt_flags(dfa, state, flags);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* only match data if not binary and the DFA flags data is expected */
|
||||
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, state, data);
|
||||
+ if (!state)
|
||||
+ return 5;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* failed at end of flags match */
|
||||
+ return 4;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt - handle path matching for mount
|
||||
+ * @profile: the confining profile
|
||||
+ * @mntpnt: string for the mntpnt (NOT NULL)
|
||||
+ * @devname: string for the devname/src_name (MAYBE NULL)
|
||||
+ * @type: string for the dev type (MAYBE NULL)
|
||||
+ * @flags: mount flags to match
|
||||
+ * @data: fs mount data (MAYBE NULL)
|
||||
+ * @binary: whether @data is binary
|
||||
+ * @perms: Returns: permission found by the match
|
||||
+ * @info: Returns: infomation string about the match for logging
|
||||
+ *
|
||||
+ * Returns: 0 on success else error
|
||||
+ */
|
||||
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
|
||||
+ const char *devname, const char *type,
|
||||
+ unsigned long flags, void *data, bool binary,
|
||||
+ struct file_perms *perms, const char **info)
|
||||
+{
|
||||
+ int pos;
|
||||
+
|
||||
+ if (!profile->policy.dfa)
|
||||
+ return -EACCES;
|
||||
+
|
||||
+ pos = do_match_mnt(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ mntpnt, devname, type, flags, data, binary, perms);
|
||||
+ if (pos) {
|
||||
+ *info = mnt_info_table[pos];
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int path_flags(struct aa_profile *profile, const struct path *path)
|
||||
+{
|
||||
+ return profile->path_flags |
|
||||
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
|
||||
+}
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ const char *name, *info = NULL;
|
||||
+ char *buffer = NULL;
|
||||
+ int binary, error;
|
||||
+
|
||||
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *dev_name, unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ flags &= MS_REC | MS_BIND;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ /* These are the flags allowed by do_change_type() */
|
||||
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE);
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
|
||||
+ &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *orig_name)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!orig_name || !*orig_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *dev_buffer = NULL;
|
||||
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
|
||||
+ int binary = 1;
|
||||
+ int error;
|
||||
+
|
||||
+ dev_name = orig_dev_name;
|
||||
+ if (type) {
|
||||
+ int requires_dev;
|
||||
+ struct file_system_type *fstype = get_fs_type(type);
|
||||
+ if (!fstype)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
|
||||
+ put_filesystem(fstype);
|
||||
+
|
||||
+ if (requires_dev) {
|
||||
+ struct path dev_path;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name) {
|
||||
+ error = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&dev_path,
|
||||
+ path_flags(profile, &dev_path),
|
||||
+ &dev_buffer, &dev_name, &info);
|
||||
+ path_put(&dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
|
||||
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(dev_buffer);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ struct path path = { mnt, mnt->mnt_root };
|
||||
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (!error && profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_UMOUNT & ~perms.allow)
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
|
||||
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ struct aa_profile *target = NULL;
|
||||
+ char *old_buffer = NULL, *new_buffer = NULL;
|
||||
+ const char *old_name, *new_name = NULL, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ error = aa_path_name(old_path, path_flags(profile, old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(new_path, path_flags(profile, new_path),
|
||||
+ &new_buffer, &new_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ new_name);
|
||||
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
|
||||
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_PIVOTROOT & perms.allow) {
|
||||
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
|
||||
+ target = x_table_lookup(profile, perms.xindex);
|
||||
+ if (!target)
|
||||
+ error = -ENOENT;
|
||||
+ else
|
||||
+ error = aa_replace_current_profile(target);
|
||||
+ }
|
||||
+ } else
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
|
||||
+ old_name, NULL, target ? target->base.name : NULL,
|
||||
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
|
||||
+ aa_put_profile(target);
|
||||
+ kfree(old_buffer);
|
||||
+ kfree(new_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,41 +0,0 @@
|
||||
From 00c72bc198aa85e5da02de2c0c4cc423c82a54f1 Mon Sep 17 00:00:00 2001
|
||||
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
|
||||
Date: Thu, 3 Aug 2017 13:46:51 -0500
|
||||
Subject: [PATCH 01/17] UBUNTU: SAUCE: (efi-lockdown) MODSIGN: Fix module
|
||||
signature verification
|
||||
|
||||
BugLink: http://bugs.launchpad.net/bugs/1712168
|
||||
|
||||
Currently mod_verify_sig() calls verify_pkcs_7_signature() with
|
||||
trusted_keys=NULL, which causes only the builtin keys to be used
|
||||
to verify the signature. This breaks self-signing of modules with
|
||||
a MOK, as the MOK is loaded into the secondary trusted keyring.
|
||||
Fix this by passing the spacial value trusted_keys=(void *)1UL,
|
||||
which tells verify_pkcs_7_signature() to use the secondary
|
||||
keyring instead.
|
||||
|
||||
(cherry picked from commit cff4523d65b848f9c41c9e998a735ae2a820da2d
|
||||
git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/fedora.git)
|
||||
[ saf: Taken from fedora commit without authorship information or much
|
||||
of a commit message; modified so that commit will describe the
|
||||
problem being fixed. ]
|
||||
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
|
||||
---
|
||||
kernel/module_signing.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
|
||||
index 937c844bee4a..d3d6f95a96b4 100644
|
||||
--- a/kernel/module_signing.c
|
||||
+++ b/kernel/module_signing.c
|
||||
@@ -81,6 +81,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
|
||||
}
|
||||
|
||||
return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
|
||||
- NULL, VERIFYING_MODULE_SIGNATURE,
|
||||
+ (void *)1UL, VERIFYING_MODULE_SIGNATURE,
|
||||
NULL, NULL);
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,51 +0,0 @@
|
||||
From c6cad5e65a23dcafa1821ca381901297664d9c64 Mon Sep 17 00:00:00 2001
|
||||
From: Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
Date: Thu, 6 Jul 2017 10:56:21 +0200
|
||||
Subject: [PATCH 02/17] apparmor: Fix shadowed local variable in
|
||||
unpack_trans_table()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
with W=2:
|
||||
|
||||
security/apparmor/policy_unpack.c: In function ‘unpack_trans_table’:
|
||||
security/apparmor/policy_unpack.c:469: warning: declaration of ‘pos’ shadows a previous local
|
||||
security/apparmor/policy_unpack.c:451: warning: shadowed declaration is here
|
||||
|
||||
Rename the old "pos" to "saved_pos" to fix this.
|
||||
|
||||
Fixes: 5379a3312024a8be ("apparmor: support v7 transition format compatible with label_parse")
|
||||
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
|
||||
Reviewed-by: Serge Hallyn <serge@hallyn.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit 966d631935a578fadb5770f17a957ee1a969d868)
|
||||
---
|
||||
security/apparmor/policy_unpack.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index c600f4dd1783..2d5a1a007b06 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -448,7 +448,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
|
||||
*/
|
||||
static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
|
||||
{
|
||||
- void *pos = e->pos;
|
||||
+ void *saved_pos = e->pos;
|
||||
|
||||
/* exec table is optional */
|
||||
if (unpack_nameX(e, AA_STRUCT, "xtable")) {
|
||||
@@ -511,7 +511,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
|
||||
|
||||
fail:
|
||||
aa_free_domain_entries(&profile->file.trans);
|
||||
- e->pos = pos;
|
||||
+ e->pos = saved_pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,32 +0,0 @@
|
||||
From 9934296cba701d429a0fc0cf071a40c8c3a1587e Mon Sep 17 00:00:00 2001
|
||||
From: Christos Gkekas <chris.gekas@gmail.com>
|
||||
Date: Sat, 8 Jul 2017 20:50:21 +0100
|
||||
Subject: [PATCH 03/17] apparmor: Fix logical error in verify_header()
|
||||
|
||||
verify_header() is currently checking whether interface version is less
|
||||
than 5 *and* greater than 7, which always evaluates to false. Instead it
|
||||
should check whether it is less than 5 *or* greater than 7.
|
||||
|
||||
Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit c54a2175e3a6bf6c697d249bba1aa729e06c7ba8)
|
||||
---
|
||||
security/apparmor/policy_unpack.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index 2d5a1a007b06..bda0dce3b582 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -832,7 +832,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
|
||||
* if not specified use previous version
|
||||
* Mask off everything that is not kernel abi version
|
||||
*/
|
||||
- if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) {
|
||||
+ if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) {
|
||||
audit_iface(NULL, NULL, NULL, "unsupported interface version",
|
||||
e, error);
|
||||
return error;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,37 +0,0 @@
|
||||
From 8b3851c7b83f32f2be9d4b48371ddf033afedf62 Mon Sep 17 00:00:00 2001
|
||||
From: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Date: Thu, 13 Jul 2017 10:39:20 +0300
|
||||
Subject: [PATCH 04/17] apparmor: Fix an error code in aafs_create()
|
||||
|
||||
We accidentally forgot to set the error code on this path. It means we
|
||||
return NULL instead of an error pointer. I looked through a bunch of
|
||||
callers and I don't think it really causes a big issue, but the
|
||||
documentation says we're supposed to return error pointers here.
|
||||
|
||||
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Acked-by: Serge Hallyn <serge@hallyn.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit aee58bf341db52a3a3563c6b972bfd4fc2d41e46)
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 853c2ec8e0c9..2caeb748070c 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -248,8 +248,10 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
|
||||
|
||||
inode_lock(dir);
|
||||
dentry = lookup_one_len(name, parent, strlen(name));
|
||||
- if (IS_ERR(dentry))
|
||||
+ if (IS_ERR(dentry)) {
|
||||
+ error = PTR_ERR(dentry);
|
||||
goto fail_lock;
|
||||
+ }
|
||||
|
||||
if (d_really_is_positive(dentry)) {
|
||||
error = -EEXIST;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,29 +0,0 @@
|
||||
From 4b56e146905bbad2c79ea92e3f49e210ca527572 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 31 Jul 2017 23:44:37 -0700
|
||||
Subject: [PATCH 05/17] apparmor: Redundant condition: prev_ns. in
|
||||
[label.c:1498]
|
||||
|
||||
Reported-by: David Binderman <dcb314@hotmail.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit d323d2c17cfcc54b6845bfc1d13bca5cef210fc7)
|
||||
---
|
||||
security/apparmor/label.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
|
||||
index e052eaba1cf6..e324f4df3e34 100644
|
||||
--- a/security/apparmor/label.c
|
||||
+++ b/security/apparmor/label.c
|
||||
@@ -1495,7 +1495,7 @@ static int aa_profile_snxprint(char *str, size_t size, struct aa_ns *view,
|
||||
view = profiles_ns(profile);
|
||||
|
||||
if (view != profile->ns &&
|
||||
- (!prev_ns || (prev_ns && *prev_ns != profile->ns))) {
|
||||
+ (!prev_ns || (*prev_ns != profile->ns))) {
|
||||
if (prev_ns)
|
||||
*prev_ns = profile->ns;
|
||||
ns_name = aa_ns_name(view, profile->ns,
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,397 +0,0 @@
|
||||
From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Tue, 18 Jul 2017 22:56:22 -0700
|
||||
Subject: [PATCH 06/17] apparmor: add the ability to mediate signals
|
||||
|
||||
Add signal mediation where the signal can be mediated based on the
|
||||
signal, direction, or the label or the peer/target. The signal perms
|
||||
are verified on a cross check to ensure policy consistency in the case
|
||||
of incremental policy load/replacement.
|
||||
|
||||
The optimization of skipping the cross check when policy is guaranteed
|
||||
to be consistent (single compile unit) remains to be done.
|
||||
|
||||
policy rules have the form of
|
||||
SIGNAL_RULE = [ QUALIFIERS ] 'signal' [ SIGNAL ACCESS PERMISSIONS ]
|
||||
[ SIGNAL SET ] [ SIGNAL PEER ]
|
||||
|
||||
SIGNAL ACCESS PERMISSIONS = SIGNAL ACCESS | SIGNAL ACCESS LIST
|
||||
|
||||
SIGNAL ACCESS LIST = '(' Comma or space separated list of SIGNAL
|
||||
ACCESS ')'
|
||||
|
||||
SIGNAL ACCESS = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' |
|
||||
'receive' )
|
||||
|
||||
SIGNAL SET = 'set' '=' '(' SIGNAL LIST ')'
|
||||
|
||||
SIGNAL LIST = Comma or space separated list of SIGNALS
|
||||
|
||||
SIGNALS = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' |
|
||||
'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' |
|
||||
'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' |
|
||||
'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' |
|
||||
'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' |
|
||||
'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32'
|
||||
)
|
||||
|
||||
SIGNAL PEER = 'peer' '=' AARE
|
||||
|
||||
eg.
|
||||
signal, # allow all signals
|
||||
signal send set=(hup, kill) peer=foo,
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
(cherry picked from commit c6bf1adaecaa719d7c56338cc43b2982214f2f44)
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 7 +++
|
||||
security/apparmor/include/apparmor.h | 1 +
|
||||
security/apparmor/include/audit.h | 2 +
|
||||
security/apparmor/include/ipc.h | 6 +++
|
||||
security/apparmor/include/sig_names.h | 95 +++++++++++++++++++++++++++++++++
|
||||
security/apparmor/ipc.c | 99 +++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/lsm.c | 21 ++++++++
|
||||
7 files changed, 231 insertions(+)
|
||||
create mode 100644 security/apparmor/include/sig_names.h
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 2caeb748070c..a5f9e1aa51f7 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "include/audit.h"
|
||||
#include "include/context.h"
|
||||
#include "include/crypto.h"
|
||||
+#include "include/ipc.h"
|
||||
#include "include/policy_ns.h"
|
||||
#include "include/label.h"
|
||||
#include "include/policy.h"
|
||||
@@ -2129,6 +2130,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
+static struct aa_sfs_entry aa_sfs_entry_signal[] = {
|
||||
+ AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct aa_sfs_entry aa_sfs_entry_domain[] = {
|
||||
AA_SFS_FILE_BOOLEAN("change_hat", 1),
|
||||
AA_SFS_FILE_BOOLEAN("change_hatv", 1),
|
||||
@@ -2179,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
|
||||
AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit),
|
||||
AA_SFS_DIR("caps", aa_sfs_entry_caps),
|
||||
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
|
||||
+ AA_SFS_DIR("signal", aa_sfs_entry_signal),
|
||||
AA_SFS_DIR("query", aa_sfs_entry_query),
|
||||
{ }
|
||||
};
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index aaf893f4e4f5..962a20a75e01 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
#define AA_CLASS_PTRACE 9
|
||||
+#define AA_CLASS_SIGNAL 10
|
||||
#define AA_CLASS_LABEL 16
|
||||
|
||||
#define AA_CLASS_LAST AA_CLASS_LABEL
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index c68839a44351..d9a156ae11b9 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -86,6 +86,7 @@ enum audit_type {
|
||||
#define OP_SHUTDOWN "socket_shutdown"
|
||||
|
||||
#define OP_PTRACE "ptrace"
|
||||
+#define OP_SIGNAL "signal"
|
||||
|
||||
#define OP_EXEC "exec"
|
||||
|
||||
@@ -126,6 +127,7 @@ struct apparmor_audit_data {
|
||||
long pos;
|
||||
const char *ns;
|
||||
} iface;
|
||||
+ int signal;
|
||||
struct {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
|
||||
index 656fdb81c8a0..5ffc218d1e74 100644
|
||||
--- a/security/apparmor/include/ipc.h
|
||||
+++ b/security/apparmor/include/ipc.h
|
||||
@@ -27,8 +27,14 @@ struct aa_profile;
|
||||
|
||||
#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
|
||||
AA_MAY_BE_READ | AA_MAY_BE_TRACED)
|
||||
+#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
|
||||
+
|
||||
+#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
|
||||
+ "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
|
||||
+ "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
|
||||
|
||||
int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
|
||||
u32 request);
|
||||
+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
|
||||
|
||||
#endif /* __AA_IPC_H */
|
||||
diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h
|
||||
new file mode 100644
|
||||
index 000000000000..0d4395f231ca
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/sig_names.h
|
||||
@@ -0,0 +1,95 @@
|
||||
+#include <linux/signal.h>
|
||||
+
|
||||
+#define SIGUNKNOWN 0
|
||||
+#define MAXMAPPED_SIG 35
|
||||
+/* provide a mapping of arch signal to internal signal # for mediation
|
||||
+ * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
|
||||
+ * map to the same entry those that may/or may not get a separate entry
|
||||
+ */
|
||||
+static const int sig_map[MAXMAPPED_SIG] = {
|
||||
+ [0] = MAXMAPPED_SIG, /* existence test */
|
||||
+ [SIGHUP] = 1,
|
||||
+ [SIGINT] = 2,
|
||||
+ [SIGQUIT] = 3,
|
||||
+ [SIGILL] = 4,
|
||||
+ [SIGTRAP] = 5, /* -, 5, - */
|
||||
+ [SIGABRT] = 6, /* SIGIOT: -, 6, - */
|
||||
+ [SIGBUS] = 7, /* 10, 7, 10 */
|
||||
+ [SIGFPE] = 8,
|
||||
+ [SIGKILL] = 9,
|
||||
+ [SIGUSR1] = 10, /* 30, 10, 16 */
|
||||
+ [SIGSEGV] = 11,
|
||||
+ [SIGUSR2] = 12, /* 31, 12, 17 */
|
||||
+ [SIGPIPE] = 13,
|
||||
+ [SIGALRM] = 14,
|
||||
+ [SIGTERM] = 15,
|
||||
+ [SIGSTKFLT] = 16, /* -, 16, - */
|
||||
+ [SIGCHLD] = 17, /* 20, 17, 18. SIGCHLD -, -, 18 */
|
||||
+ [SIGCONT] = 18, /* 19, 18, 25 */
|
||||
+ [SIGSTOP] = 19, /* 17, 19, 23 */
|
||||
+ [SIGTSTP] = 20, /* 18, 20, 24 */
|
||||
+ [SIGTTIN] = 21, /* 21, 21, 26 */
|
||||
+ [SIGTTOU] = 22, /* 22, 22, 27 */
|
||||
+ [SIGURG] = 23, /* 16, 23, 21 */
|
||||
+ [SIGXCPU] = 24, /* 24, 24, 30 */
|
||||
+ [SIGXFSZ] = 25, /* 25, 25, 31 */
|
||||
+ [SIGVTALRM] = 26, /* 26, 26, 28 */
|
||||
+ [SIGPROF] = 27, /* 27, 27, 29 */
|
||||
+ [SIGWINCH] = 28, /* 28, 28, 20 */
|
||||
+ [SIGIO] = 29, /* SIGPOLL: 23, 29, 22 */
|
||||
+ [SIGPWR] = 30, /* 29, 30, 19. SIGINFO 29, -, - */
|
||||
+#ifdef SIGSYS
|
||||
+ [SIGSYS] = 31, /* 12, 31, 12. often SIG LOST/UNUSED */
|
||||
+#endif
|
||||
+#ifdef SIGEMT
|
||||
+ [SIGEMT] = 32, /* 7, - , 7 */
|
||||
+#endif
|
||||
+#if defined(SIGLOST) && SIGPWR != SIGLOST /* sparc */
|
||||
+ [SIGLOST] = 33, /* unused on Linux */
|
||||
+#endif
|
||||
+#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS
|
||||
+ [SIGUNUSED] = 34, /* -, 31, - */
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+/* this table is ordered post sig_map[sig] mapping */
|
||||
+static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
+ "unknown",
|
||||
+ "hup",
|
||||
+ "int",
|
||||
+ "quit",
|
||||
+ "ill",
|
||||
+ "trap",
|
||||
+ "abrt",
|
||||
+ "bus",
|
||||
+ "fpe",
|
||||
+ "kill",
|
||||
+ "usr1",
|
||||
+ "segv",
|
||||
+ "usr2",
|
||||
+ "pipe",
|
||||
+ "alrm",
|
||||
+ "term",
|
||||
+ "stkflt",
|
||||
+ "chld",
|
||||
+ "cont",
|
||||
+ "stop",
|
||||
+ "stp",
|
||||
+ "ttin",
|
||||
+ "ttou",
|
||||
+ "urg",
|
||||
+ "xcpu",
|
||||
+ "xfsz",
|
||||
+ "vtalrm",
|
||||
+ "prof",
|
||||
+ "winch",
|
||||
+ "io",
|
||||
+ "pwr",
|
||||
+ "sys",
|
||||
+ "emt",
|
||||
+ "lost",
|
||||
+ "unused",
|
||||
+
|
||||
+ "exists", /* always last existence test mapped to MAXMAPPED_SIG */
|
||||
+};
|
||||
+
|
||||
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
|
||||
index 11e66b5bbc42..66fb9ede9447 100644
|
||||
--- a/security/apparmor/ipc.c
|
||||
+++ b/security/apparmor/ipc.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "include/context.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/ipc.h"
|
||||
+#include "include/sig_names.h"
|
||||
|
||||
/**
|
||||
* audit_ptrace_mask - convert mask to permission string
|
||||
@@ -121,3 +122,101 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
|
||||
}
|
||||
|
||||
|
||||
+static inline int map_signal_num(int sig)
|
||||
+{
|
||||
+ if (sig > SIGRTMAX)
|
||||
+ return SIGUNKNOWN;
|
||||
+ else if (sig >= SIGRTMIN)
|
||||
+ return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */
|
||||
+ else if (sig <= MAXMAPPED_SIG)
|
||||
+ return sig_map[sig];
|
||||
+ return SIGUNKNOWN;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_file_mask - convert mask to permission string
|
||||
+ * @buffer: buffer to write string to (NOT NULL)
|
||||
+ * @mask: permission mask to convert
|
||||
+ */
|
||||
+static void audit_signal_mask(struct audit_buffer *ab, u32 mask)
|
||||
+{
|
||||
+ if (mask & MAY_READ)
|
||||
+ audit_log_string(ab, "receive");
|
||||
+ if (mask & MAY_WRITE)
|
||||
+ audit_log_string(ab, "send");
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_cb - call back for signal specific audit fields
|
||||
+ * @ab: audit_buffer (NOT NULL)
|
||||
+ * @va: audit struct to audit values of (NOT NULL)
|
||||
+ */
|
||||
+static void audit_signal_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ if (aad(sa)->request & AA_SIGNAL_PERM_MASK) {
|
||||
+ audit_log_format(ab, " requested_mask=");
|
||||
+ audit_signal_mask(ab, aad(sa)->request);
|
||||
+ if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) {
|
||||
+ audit_log_format(ab, " denied_mask=");
|
||||
+ audit_signal_mask(ab, aad(sa)->denied);
|
||||
+ }
|
||||
+ }
|
||||
+ if (aad(sa)->signal <= MAXMAPPED_SIG)
|
||||
+ audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
|
||||
+ else
|
||||
+ audit_log_format(ab, " signal=rtmin+%d",
|
||||
+ aad(sa)->signal - 128);
|
||||
+ audit_log_format(ab, " peer=");
|
||||
+ aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
|
||||
+ FLAGS_NONE, GFP_ATOMIC);
|
||||
+}
|
||||
+
|
||||
+/* TODO: update to handle compound name&name2, conditionals */
|
||||
+static void profile_match_signal(struct aa_profile *profile, const char *label,
|
||||
+ int signal, struct aa_perms *perms)
|
||||
+{
|
||||
+ unsigned int state;
|
||||
+
|
||||
+ /* TODO: secondary cache check <profile, profile, perm> */
|
||||
+ state = aa_dfa_next(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_SIGNAL],
|
||||
+ signal);
|
||||
+ state = aa_dfa_match(profile->policy.dfa, state, label);
|
||||
+ aa_compute_perms(profile->policy.dfa, state, perms);
|
||||
+}
|
||||
+
|
||||
+static int profile_signal_perm(struct aa_profile *profile,
|
||||
+ struct aa_profile *peer, u32 request,
|
||||
+ struct common_audit_data *sa)
|
||||
+{
|
||||
+ struct aa_perms perms;
|
||||
+
|
||||
+ if (profile_unconfined(profile) ||
|
||||
+ !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
|
||||
+ return 0;
|
||||
+
|
||||
+ aad(sa)->peer = &peer->label;
|
||||
+ profile_match_signal(profile, peer->base.hname, aad(sa)->signal,
|
||||
+ &perms);
|
||||
+ aa_apply_modes_to_perms(profile, &perms);
|
||||
+ return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
|
||||
+}
|
||||
+
|
||||
+static int aa_signal_cross_perm(struct aa_profile *sender,
|
||||
+ struct aa_profile *target,
|
||||
+ struct common_audit_data *sa)
|
||||
+{
|
||||
+ return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa),
|
||||
+ profile_signal_perm(target, sender, MAY_READ, sa));
|
||||
+}
|
||||
+
|
||||
+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
|
||||
+{
|
||||
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL);
|
||||
+
|
||||
+ aad(&sa)->signal = map_signal_num(sig);
|
||||
+ return xcheck_labels_profiles(sender, target, aa_signal_cross_perm,
|
||||
+ &sa);
|
||||
+}
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 867bcd154c7e..af22f3dfbcce 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -656,6 +656,26 @@ static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
|
||||
+ int sig, u32 secid)
|
||||
+{
|
||||
+ struct aa_label *cl, *tl;
|
||||
+ int error;
|
||||
+
|
||||
+ if (secid)
|
||||
+ /* TODO: after secid to label mapping is done.
|
||||
+ * Dealing with USB IO specific behavior
|
||||
+ */
|
||||
+ return 0;
|
||||
+ cl = __begin_current_label_crit_section();
|
||||
+ tl = aa_get_task_label(target);
|
||||
+ error = aa_may_signal(cl, tl, sig);
|
||||
+ aa_put_label(tl);
|
||||
+ __end_current_label_crit_section(cl);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||
@@ -697,6 +717,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),
|
||||
|
||||
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
|
||||
+ LSM_HOOK_INIT(task_kill, apparmor_task_kill),
|
||||
};
|
||||
|
||||
/*
|
||||
--
|
||||
2.11.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,71 +0,0 @@
|
||||
From 763d17c9a18b0df7dbec2740f10dc40d378e3cc1 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sun, 6 Aug 2017 05:36:40 -0700
|
||||
Subject: [PATCH 08/17] apparmor: cleanup conditional check for label in
|
||||
label_print
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
(cherry picked from commit 7e57939b9d67dcfc2c8348fd0e2c76a2f0349c75)
|
||||
---
|
||||
security/apparmor/label.c | 22 ++++++++--------------
|
||||
1 file changed, 8 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
|
||||
index e324f4df3e34..38be7a89cc31 100644
|
||||
--- a/security/apparmor/label.c
|
||||
+++ b/security/apparmor/label.c
|
||||
@@ -1450,9 +1450,11 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
|
||||
* cached label name is present and visible
|
||||
* @label->hname only exists if label is namespace hierachical
|
||||
*/
|
||||
-static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label)
|
||||
+static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
|
||||
+ int flags)
|
||||
{
|
||||
- if (label->hname && labels_ns(label) == ns)
|
||||
+ if (label->hname && (!ns || labels_ns(label) == ns) &&
|
||||
+ !(flags & ~FLAG_SHOW_MODE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1710,10 +1712,8 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
|
||||
AA_BUG(!ab);
|
||||
AA_BUG(!label);
|
||||
|
||||
- if (!ns)
|
||||
- ns = labels_ns(label);
|
||||
-
|
||||
- if (!use_label_hname(ns, label) || display_mode(ns, label, flags)) {
|
||||
+ if (!use_label_hname(ns, label, flags) ||
|
||||
+ display_mode(ns, label, flags)) {
|
||||
len = aa_label_asxprint(&name, ns, label, flags, gfp);
|
||||
if (len == -1) {
|
||||
AA_DEBUG("label print error");
|
||||
@@ -1738,10 +1738,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
|
||||
AA_BUG(!f);
|
||||
AA_BUG(!label);
|
||||
|
||||
- if (!ns)
|
||||
- ns = labels_ns(label);
|
||||
-
|
||||
- if (!use_label_hname(ns, label)) {
|
||||
+ if (!use_label_hname(ns, label, flags)) {
|
||||
char *str;
|
||||
int len;
|
||||
|
||||
@@ -1764,10 +1761,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
|
||||
{
|
||||
AA_BUG(!label);
|
||||
|
||||
- if (!ns)
|
||||
- ns = labels_ns(label);
|
||||
-
|
||||
- if (!use_label_hname(ns, label)) {
|
||||
+ if (!use_label_hname(ns, label, flags)) {
|
||||
char *str;
|
||||
int len;
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,63 +0,0 @@
|
||||
From 6b092bbbf9e17b10f709d11b3bc2d7e493617934 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sun, 6 Aug 2017 05:39:08 -0700
|
||||
Subject: [PATCH 09/17] apparmor: add support for absolute root view based
|
||||
labels
|
||||
|
||||
With apparmor policy virtualization based on policy namespace View's
|
||||
we don't generally want/need absolute root based views, however there
|
||||
are cases like debugging and some secid based conversions where
|
||||
using a root based view is important.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
(cherry picked from commit eadfbf0898eda94cee0d982626aa24a3146db48b)
|
||||
---
|
||||
security/apparmor/include/label.h | 1 +
|
||||
security/apparmor/label.c | 10 +++++++++-
|
||||
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
|
||||
index 9a283b722755..af22dcbbcb8a 100644
|
||||
--- a/security/apparmor/include/label.h
|
||||
+++ b/security/apparmor/include/label.h
|
||||
@@ -310,6 +310,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp);
|
||||
#define FLAG_SHOW_MODE 1
|
||||
#define FLAG_VIEW_SUBNS 2
|
||||
#define FLAG_HIDDEN_UNCONFINED 4
|
||||
+#define FLAG_ABS_ROOT 8
|
||||
int aa_label_snxprint(char *str, size_t size, struct aa_ns *view,
|
||||
struct aa_label *label, int flags);
|
||||
int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
|
||||
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
|
||||
index 38be7a89cc31..52b4ef14840d 100644
|
||||
--- a/security/apparmor/label.c
|
||||
+++ b/security/apparmor/label.c
|
||||
@@ -1607,8 +1607,13 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
|
||||
AA_BUG(!str && size != 0);
|
||||
AA_BUG(!label);
|
||||
|
||||
- if (!ns)
|
||||
+ if (flags & FLAG_ABS_ROOT) {
|
||||
+ ns = root_ns;
|
||||
+ len = snprintf(str, size, "=");
|
||||
+ update_for_len(total, len, size, str);
|
||||
+ } else if (!ns) {
|
||||
ns = labels_ns(label);
|
||||
+ }
|
||||
|
||||
label_for_each(i, label, profile) {
|
||||
if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
|
||||
@@ -1868,6 +1873,9 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
|
||||
if (*str == '&')
|
||||
str++;
|
||||
}
|
||||
+ if (*str == '=')
|
||||
+ base = &root_ns->unconfined->label;
|
||||
+
|
||||
error = vec_setup(profile, vec, len, gfp);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,219 +0,0 @@
|
||||
From aa4b6bded85552bc5f9f22d2e18ce86c5c17947c Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Tue, 18 Jul 2017 23:37:18 -0700
|
||||
Subject: [PATCH 10/17] apparmor: make policy_unpack able to audit different
|
||||
info messages
|
||||
|
||||
Switch unpack auditing to using the generic name field in the audit
|
||||
struct and make it so we can start adding new info messages about
|
||||
why an unpack failed.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
(cherry picked from commit 1489d896c5649e9ce1b6000b4857f8baa7a6ab63)
|
||||
---
|
||||
security/apparmor/include/audit.h | 4 +--
|
||||
security/apparmor/policy_unpack.c | 52 ++++++++++++++++++++++++++++-----------
|
||||
2 files changed, 40 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index c3fe1c5ef3bc..620e81169659 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -127,9 +127,9 @@ struct apparmor_audit_data {
|
||||
} fs;
|
||||
};
|
||||
struct {
|
||||
- const char *name;
|
||||
- long pos;
|
||||
+ struct aa_profile *profile;
|
||||
const char *ns;
|
||||
+ long pos;
|
||||
} iface;
|
||||
int signal;
|
||||
struct {
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index bda0dce3b582..4ede87c30f8b 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -85,9 +85,9 @@ static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
audit_log_format(ab, " ns=");
|
||||
audit_log_untrustedstring(ab, aad(sa)->iface.ns);
|
||||
}
|
||||
- if (aad(sa)->iface.name) {
|
||||
+ if (aad(sa)->name) {
|
||||
audit_log_format(ab, " name=");
|
||||
- audit_log_untrustedstring(ab, aad(sa)->iface.name);
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->name);
|
||||
}
|
||||
if (aad(sa)->iface.pos)
|
||||
audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
|
||||
@@ -114,9 +114,9 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
|
||||
aad(&sa)->iface.pos = e->pos - e->start;
|
||||
aad(&sa)->iface.ns = ns_name;
|
||||
if (new)
|
||||
- aad(&sa)->iface.name = new->base.hname;
|
||||
+ aad(&sa)->name = new->base.hname;
|
||||
else
|
||||
- aad(&sa)->iface.name = name;
|
||||
+ aad(&sa)->name = name;
|
||||
aad(&sa)->info = info;
|
||||
aad(&sa)->error = error;
|
||||
|
||||
@@ -583,6 +583,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
const char *tmpname, *tmpns = NULL, *name = NULL;
|
||||
+ const char *info = "failed to unpack profile";
|
||||
size_t ns_len;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
@@ -604,8 +605,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len);
|
||||
if (tmpns) {
|
||||
*ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL);
|
||||
- if (!*ns_name)
|
||||
+ if (!*ns_name) {
|
||||
+ info = "out of memory";
|
||||
goto fail;
|
||||
+ }
|
||||
name = tmpname;
|
||||
}
|
||||
|
||||
@@ -624,12 +627,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (IS_ERR(profile->xmatch)) {
|
||||
error = PTR_ERR(profile->xmatch);
|
||||
profile->xmatch = NULL;
|
||||
+ info = "bad xmatch";
|
||||
goto fail;
|
||||
}
|
||||
/* xmatch_len is not optional if xmatch is set */
|
||||
if (profile->xmatch) {
|
||||
- if (!unpack_u32(e, &tmp, NULL))
|
||||
+ if (!unpack_u32(e, &tmp, NULL)) {
|
||||
+ info = "missing xmatch len";
|
||||
goto fail;
|
||||
+ }
|
||||
profile->xmatch_len = tmp;
|
||||
}
|
||||
|
||||
@@ -637,8 +643,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
(void) unpack_str(e, &profile->disconnected, "disconnected");
|
||||
|
||||
/* per profile debug flags (complain, audit) */
|
||||
- if (!unpack_nameX(e, AA_STRUCT, "flags"))
|
||||
+ if (!unpack_nameX(e, AA_STRUCT, "flags")) {
|
||||
+ info = "profile missing flags";
|
||||
goto fail;
|
||||
+ }
|
||||
+ info = "failed to unpack profile flags";
|
||||
if (!unpack_u32(e, &tmp, NULL))
|
||||
goto fail;
|
||||
if (tmp & PACKED_FLAG_HAT)
|
||||
@@ -667,6 +676,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
/* set a default value if path_flags field is not present */
|
||||
profile->path_flags = PATH_MEDIATE_DELETED;
|
||||
|
||||
+ info = "failed to unpack profile capabilities";
|
||||
if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
|
||||
goto fail;
|
||||
if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
|
||||
@@ -676,6 +686,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (!unpack_u32(e, &tmpcap.cap[0], NULL))
|
||||
goto fail;
|
||||
|
||||
+ info = "failed to unpack upper profile capabilities";
|
||||
if (unpack_nameX(e, AA_STRUCT, "caps64")) {
|
||||
/* optional upper half of 64 bit caps */
|
||||
if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
|
||||
@@ -690,6 +701,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ info = "failed to unpack extended profile capabilities";
|
||||
if (unpack_nameX(e, AA_STRUCT, "capsx")) {
|
||||
/* optional extended caps mediation mask */
|
||||
if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
|
||||
@@ -700,11 +712,14 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- if (!unpack_rlimits(e, profile))
|
||||
+ if (!unpack_rlimits(e, profile)) {
|
||||
+ info = "failed to unpack profile rlimits";
|
||||
goto fail;
|
||||
+ }
|
||||
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
+ info = "failed to unpack policydb";
|
||||
profile->policy.dfa = unpack_dfa(e);
|
||||
if (IS_ERR(profile->policy.dfa)) {
|
||||
error = PTR_ERR(profile->policy.dfa);
|
||||
@@ -734,6 +749,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (IS_ERR(profile->file.dfa)) {
|
||||
error = PTR_ERR(profile->file.dfa);
|
||||
profile->file.dfa = NULL;
|
||||
+ info = "failed to unpack profile file rules";
|
||||
goto fail;
|
||||
} else if (profile->file.dfa) {
|
||||
if (!unpack_u32(e, &profile->file.start, "dfa_start"))
|
||||
@@ -746,10 +762,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
} else
|
||||
profile->file.dfa = aa_get_dfa(nulldfa);
|
||||
|
||||
- if (!unpack_trans_table(e, profile))
|
||||
+ if (!unpack_trans_table(e, profile)) {
|
||||
+ info = "failed to unpack profile transition table";
|
||||
goto fail;
|
||||
+ }
|
||||
|
||||
if (unpack_nameX(e, AA_STRUCT, "data")) {
|
||||
+ info = "out of memory";
|
||||
profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
|
||||
if (!profile->data)
|
||||
goto fail;
|
||||
@@ -761,8 +780,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
params.hashfn = strhash;
|
||||
params.obj_cmpfn = datacmp;
|
||||
|
||||
- if (rhashtable_init(profile->data, ¶ms))
|
||||
+ if (rhashtable_init(profile->data, ¶ms)) {
|
||||
+ info = "failed to init key, value hash table";
|
||||
goto fail;
|
||||
+ }
|
||||
|
||||
while (unpack_strdup(e, &key, NULL)) {
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
@@ -784,12 +805,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
profile->data->p);
|
||||
}
|
||||
|
||||
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
|
||||
+ info = "failed to unpack end of key, value data table";
|
||||
goto fail;
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
|
||||
+ info = "failed to unpack end of profile";
|
||||
goto fail;
|
||||
+ }
|
||||
|
||||
return profile;
|
||||
|
||||
@@ -798,8 +823,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
name = NULL;
|
||||
else if (!name)
|
||||
name = "unknown";
|
||||
- audit_iface(profile, NULL, name, "failed to unpack profile", e,
|
||||
- error);
|
||||
+ audit_iface(profile, NULL, name, info, e, error);
|
||||
aa_free_profile(profile);
|
||||
|
||||
return ERR_PTR(error);
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,78 +0,0 @@
|
||||
From ba3f778a2ef31454032c2ca9c99d9212feb4dcf1 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Tue, 18 Jul 2017 23:41:13 -0700
|
||||
Subject: [PATCH 11/17] apparmor: add more debug asserts to apparmorfs
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
(cherry picked from commit 52c9542126fb04df1f12c605b6c22719c9096794)
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 8fa6c898c44b..7acea14c850b 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1446,6 +1446,10 @@ void __aafs_profile_migrate_dents(struct aa_profile *old,
|
||||
{
|
||||
int i;
|
||||
|
||||
+ AA_BUG(!old);
|
||||
+ AA_BUG(!new);
|
||||
+ AA_BUG(!mutex_is_locked(&profiles_ns(old)->lock));
|
||||
+
|
||||
for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
|
||||
new->dents[i] = old->dents[i];
|
||||
if (new->dents[i])
|
||||
@@ -1509,6 +1513,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
|
||||
struct dentry *dent = NULL, *dir;
|
||||
int error;
|
||||
|
||||
+ AA_BUG(!profile);
|
||||
+ AA_BUG(!mutex_is_locked(&profiles_ns(profile)->lock));
|
||||
+
|
||||
if (!parent) {
|
||||
struct aa_profile *p;
|
||||
p = aa_deref_parent(profile);
|
||||
@@ -1734,6 +1741,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns)
|
||||
|
||||
if (!ns)
|
||||
return;
|
||||
+ AA_BUG(!mutex_is_locked(&ns->lock));
|
||||
|
||||
list_for_each_entry(child, &ns->base.profiles, base.list)
|
||||
__aafs_profile_rmdir(child);
|
||||
@@ -1906,6 +1914,10 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
|
||||
{
|
||||
struct aa_ns *parent, *next;
|
||||
|
||||
+ AA_BUG(!root);
|
||||
+ AA_BUG(!ns);
|
||||
+ AA_BUG(ns != root && !mutex_is_locked(&ns->parent->lock));
|
||||
+
|
||||
/* is next namespace a child */
|
||||
if (!list_empty(&ns->sub_ns)) {
|
||||
next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
|
||||
@@ -1940,6 +1952,9 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
|
||||
static struct aa_profile *__first_profile(struct aa_ns *root,
|
||||
struct aa_ns *ns)
|
||||
{
|
||||
+ AA_BUG(!root);
|
||||
+ AA_BUG(ns && !mutex_is_locked(&ns->lock));
|
||||
+
|
||||
for (; ns; ns = __next_ns(root, ns)) {
|
||||
if (!list_empty(&ns->base.profiles))
|
||||
return list_first_entry(&ns->base.profiles,
|
||||
@@ -1962,6 +1977,8 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
|
||||
struct aa_profile *parent;
|
||||
struct aa_ns *ns = p->ns;
|
||||
|
||||
+ AA_BUG(!mutex_is_locked(&profiles_ns(p)->lock));
|
||||
+
|
||||
/* is next profile a child */
|
||||
if (!list_empty(&p->base.profiles))
|
||||
return list_first_entry(&p->base.profiles, typeof(*p),
|
||||
--
|
||||
2.11.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
||||
From 50d30adbef98a0b6cc531a9413d05f564eb633ee Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 Aug 2017 08:59:57 -0700
|
||||
Subject: [PATCH 13/17] apparmor: move new_null_profile to after profile lookup
|
||||
fns()
|
||||
|
||||
new_null_profile will need to use some of the profile lookup fns()
|
||||
so move instead of doing forward fn declarations.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit cf1e50dfc6f627bc2989b57076b129c330fb3f0a)
|
||||
---
|
||||
security/apparmor/policy.c | 158 ++++++++++++++++++++++-----------------------
|
||||
1 file changed, 79 insertions(+), 79 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index 244ea4a4a8f0..a81a384a63b1 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -289,85 +289,6 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * aa_new_null_profile - create or find a null-X learning profile
|
||||
- * @parent: profile that caused this profile to be created (NOT NULL)
|
||||
- * @hat: true if the null- learning profile is a hat
|
||||
- * @base: name to base the null profile off of
|
||||
- * @gfp: type of allocation
|
||||
- *
|
||||
- * Find/Create a null- complain mode profile used in learning mode. The
|
||||
- * name of the profile is unique and follows the format of parent//null-XXX.
|
||||
- * where XXX is based on the @name or if that fails or is not supplied
|
||||
- * a unique number
|
||||
- *
|
||||
- * null profiles are added to the profile list but the list does not
|
||||
- * hold a count on them so that they are automatically released when
|
||||
- * not in use.
|
||||
- *
|
||||
- * Returns: new refcounted profile else NULL on failure
|
||||
- */
|
||||
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
|
||||
- const char *base, gfp_t gfp)
|
||||
-{
|
||||
- struct aa_profile *profile;
|
||||
- char *name;
|
||||
-
|
||||
- AA_BUG(!parent);
|
||||
-
|
||||
- if (base) {
|
||||
- name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
|
||||
- gfp);
|
||||
- if (name) {
|
||||
- sprintf(name, "%s//null-%s", parent->base.hname, base);
|
||||
- goto name;
|
||||
- }
|
||||
- /* fall through to try shorter uniq */
|
||||
- }
|
||||
-
|
||||
- name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
|
||||
- if (!name)
|
||||
- return NULL;
|
||||
- sprintf(name, "%s//null-%x", parent->base.hname,
|
||||
- atomic_inc_return(&parent->ns->uniq_null));
|
||||
-
|
||||
-name:
|
||||
- /* lookup to see if this is a dup creation */
|
||||
- profile = aa_find_child(parent, basename(name));
|
||||
- if (profile)
|
||||
- goto out;
|
||||
-
|
||||
- profile = aa_alloc_profile(name, NULL, gfp);
|
||||
- if (!profile)
|
||||
- goto fail;
|
||||
-
|
||||
- profile->mode = APPARMOR_COMPLAIN;
|
||||
- profile->label.flags |= FLAG_NULL;
|
||||
- if (hat)
|
||||
- profile->label.flags |= FLAG_HAT;
|
||||
- profile->path_flags = parent->path_flags;
|
||||
-
|
||||
- /* released on free_profile */
|
||||
- rcu_assign_pointer(profile->parent, aa_get_profile(parent));
|
||||
- profile->ns = aa_get_ns(parent->ns);
|
||||
- profile->file.dfa = aa_get_dfa(nulldfa);
|
||||
- profile->policy.dfa = aa_get_dfa(nulldfa);
|
||||
-
|
||||
- mutex_lock(&profile->ns->lock);
|
||||
- __add_profile(&parent->base.profiles, profile);
|
||||
- mutex_unlock(&profile->ns->lock);
|
||||
-
|
||||
- /* refcount released by caller */
|
||||
-out:
|
||||
- kfree(name);
|
||||
-
|
||||
- return profile;
|
||||
-
|
||||
-fail:
|
||||
- aa_free_profile(profile);
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
/* TODO: profile accounting - setup in remove */
|
||||
|
||||
/**
|
||||
@@ -559,6 +480,85 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
|
||||
}
|
||||
|
||||
/**
|
||||
+ * aa_new_null_profile - create or find a null-X learning profile
|
||||
+ * @parent: profile that caused this profile to be created (NOT NULL)
|
||||
+ * @hat: true if the null- learning profile is a hat
|
||||
+ * @base: name to base the null profile off of
|
||||
+ * @gfp: type of allocation
|
||||
+ *
|
||||
+ * Find/Create a null- complain mode profile used in learning mode. The
|
||||
+ * name of the profile is unique and follows the format of parent//null-XXX.
|
||||
+ * where XXX is based on the @name or if that fails or is not supplied
|
||||
+ * a unique number
|
||||
+ *
|
||||
+ * null profiles are added to the profile list but the list does not
|
||||
+ * hold a count on them so that they are automatically released when
|
||||
+ * not in use.
|
||||
+ *
|
||||
+ * Returns: new refcounted profile else NULL on failure
|
||||
+ */
|
||||
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
|
||||
+ const char *base, gfp_t gfp)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ char *name;
|
||||
+
|
||||
+ AA_BUG(!parent);
|
||||
+
|
||||
+ if (base) {
|
||||
+ name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
|
||||
+ gfp);
|
||||
+ if (name) {
|
||||
+ sprintf(name, "%s//null-%s", parent->base.hname, base);
|
||||
+ goto name;
|
||||
+ }
|
||||
+ /* fall through to try shorter uniq */
|
||||
+ }
|
||||
+
|
||||
+ name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
|
||||
+ if (!name)
|
||||
+ return NULL;
|
||||
+ sprintf(name, "%s//null-%x", parent->base.hname,
|
||||
+ atomic_inc_return(&parent->ns->uniq_null));
|
||||
+
|
||||
+name:
|
||||
+ /* lookup to see if this is a dup creation */
|
||||
+ profile = aa_find_child(parent, basename(name));
|
||||
+ if (profile)
|
||||
+ goto out;
|
||||
+
|
||||
+ profile = aa_alloc_profile(name, NULL, gfp);
|
||||
+ if (!profile)
|
||||
+ goto fail;
|
||||
+
|
||||
+ profile->mode = APPARMOR_COMPLAIN;
|
||||
+ profile->label.flags |= FLAG_NULL;
|
||||
+ if (hat)
|
||||
+ profile->label.flags |= FLAG_HAT;
|
||||
+ profile->path_flags = parent->path_flags;
|
||||
+
|
||||
+ /* released on free_profile */
|
||||
+ rcu_assign_pointer(profile->parent, aa_get_profile(parent));
|
||||
+ profile->ns = aa_get_ns(parent->ns);
|
||||
+ profile->file.dfa = aa_get_dfa(nulldfa);
|
||||
+ profile->policy.dfa = aa_get_dfa(nulldfa);
|
||||
+
|
||||
+ mutex_lock(&profile->ns->lock);
|
||||
+ __add_profile(&parent->base.profiles, profile);
|
||||
+ mutex_unlock(&profile->ns->lock);
|
||||
+
|
||||
+ /* refcount released by caller */
|
||||
+out:
|
||||
+ kfree(name);
|
||||
+
|
||||
+ return profile;
|
||||
+
|
||||
+fail:
|
||||
+ aa_free_profile(profile);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* replacement_allowed - test to see if replacement is allowed
|
||||
* @profile: profile to test if it can be replaced (MAYBE NULL)
|
||||
* @noreplace: true if replacement shouldn't be allowed but addition is okay
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,60 +0,0 @@
|
||||
From ab3b869791b6122c7be7e68ca4c08e2c2e8815ac Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 Aug 2017 05:40:49 -0700
|
||||
Subject: [PATCH 14/17] apparmor: fix race condition in null profile creation
|
||||
|
||||
There is a race when null- profile is being created between the
|
||||
initial lookup/creation of the profile and lock/addition of the
|
||||
profile. This could result in multiple version of a profile being
|
||||
added to the list which need to be removed/replaced.
|
||||
|
||||
Since these are learning profile their is no affect on mediation.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit 3aa3de2a4fb8f33ec62b00998bc6b6c6850d41b1)
|
||||
---
|
||||
security/apparmor/policy.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index a81a384a63b1..4243b0c3f0e4 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -500,7 +500,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
|
||||
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
|
||||
const char *base, gfp_t gfp)
|
||||
{
|
||||
- struct aa_profile *profile;
|
||||
+ struct aa_profile *p, *profile;
|
||||
+ const char *bname;
|
||||
char *name;
|
||||
|
||||
AA_BUG(!parent);
|
||||
@@ -523,7 +524,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
|
||||
|
||||
name:
|
||||
/* lookup to see if this is a dup creation */
|
||||
- profile = aa_find_child(parent, basename(name));
|
||||
+ bname = basename(name);
|
||||
+ profile = aa_find_child(parent, bname);
|
||||
if (profile)
|
||||
goto out;
|
||||
|
||||
@@ -544,7 +546,13 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
|
||||
profile->policy.dfa = aa_get_dfa(nulldfa);
|
||||
|
||||
mutex_lock(&profile->ns->lock);
|
||||
- __add_profile(&parent->base.profiles, profile);
|
||||
+ p = __find_child(&parent->base.profiles, bname);
|
||||
+ if (p) {
|
||||
+ aa_free_profile(profile);
|
||||
+ profile = aa_get_profile(p);
|
||||
+ } else {
|
||||
+ __add_profile(&parent->base.profiles, profile);
|
||||
+ }
|
||||
mutex_unlock(&profile->ns->lock);
|
||||
|
||||
/* refcount released by caller */
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,36 +0,0 @@
|
||||
From 7f2cdd6453518ff76c3855255c91306a2b928c9a Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 Aug 2017 05:48:06 -0700
|
||||
Subject: [PATCH 15/17] apparmor: ensure unconfined profiles have dfas
|
||||
initialized
|
||||
|
||||
Generally unconfined has early bailout tests and does not need the
|
||||
dfas initialized, however if an early bailout test is ever missed
|
||||
it will result in an oops.
|
||||
|
||||
Be defensive and initialize the unconfined profile to have null dfas
|
||||
(no permission) so if an early bailout test is missed we fail
|
||||
closed (no perms granted) instead of oopsing.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit 034ad2d248927722bdcd1aedb62634cdc2049113)
|
||||
---
|
||||
security/apparmor/policy_ns.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
|
||||
index 351d3bab3a3d..62a3589c62ab 100644
|
||||
--- a/security/apparmor/policy_ns.c
|
||||
+++ b/security/apparmor/policy_ns.c
|
||||
@@ -112,6 +112,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
|
||||
ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
|
||||
FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
|
||||
ns->unconfined->mode = APPARMOR_UNCONFINED;
|
||||
+ ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
|
||||
+ ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
|
||||
|
||||
/* ns and ns->unconfined share ns->unconfined refcount */
|
||||
ns->unconfined->ns = ns;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,39 +0,0 @@
|
||||
From 8daf877473653c06a28c86bf72d63ce7e5c1d542 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 Aug 2017 09:33:48 -0700
|
||||
Subject: [PATCH 16/17] apparmor: fix incorrect type assignment when freeing
|
||||
proxies
|
||||
|
||||
sparse reports
|
||||
|
||||
poisoning the proxy->label before freeing the struct is resulting in
|
||||
a sparse build warning.
|
||||
../security/apparmor/label.c:52:30: warning: incorrect type in assignment (different address spaces)
|
||||
../security/apparmor/label.c:52:30: expected struct aa_label [noderef] <asn:4>*label
|
||||
../security/apparmor/label.c:52:30: got struct aa_label *<noident>
|
||||
|
||||
fix with RCU_INIT_POINTER as this is one of those cases where
|
||||
rcu_assign_pointer() is not needed.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
(cherry picked from commit 76e22e212a850bbd16cf49f9c586d4635507e0b5)
|
||||
---
|
||||
security/apparmor/label.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
|
||||
index 52b4ef14840d..c5b99b954580 100644
|
||||
--- a/security/apparmor/label.c
|
||||
+++ b/security/apparmor/label.c
|
||||
@@ -49,7 +49,7 @@ static void free_proxy(struct aa_proxy *proxy)
|
||||
/* p->label will not updated any more as p is dead */
|
||||
aa_put_label(rcu_dereference_protected(proxy->label, true));
|
||||
memset(proxy, 0, sizeof(*proxy));
|
||||
- proxy->label = (struct aa_label *) PROXY_POISON;
|
||||
+ RCU_INIT_POINTER(proxy->label, (struct aa_label *)PROXY_POISON);
|
||||
kfree(proxy);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
The old out of tree patches have been dropped.
|
||||
|
||||
This series is a backport of the patches currently in security-next
|
||||
scheduled for 4.14, with the exception of the last patch for af_unix
|
||||
mediation.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
This is based on v4.14 final
|
||||
|
||||
base socket mediation and af_unix-mediation are the last two remaining
|
||||
patches that are out of tree
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user