mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 14:55:10 +00:00
Compare commits
117 Commits
v2.11.2
...
git-conver
Author | SHA1 | Date | |
---|---|---|---|
|
df0f20f32b | ||
|
c4a4e5bb82 | ||
|
d2f7f21b04 | ||
|
eab153a7e9 | ||
|
f737cc3444 | ||
|
7aeebcbb60 | ||
|
62e91696ee | ||
|
ffeb6c02a5 | ||
|
ad94da321b | ||
|
9a69ec2c48 | ||
|
6ce2768115 | ||
|
4961fcb6ba | ||
|
881cf7bddc | ||
|
74178418ad | ||
|
a32a9aa6d1 | ||
|
12fc3f0d4d | ||
|
1d896e014c | ||
|
76a8923ce4 | ||
|
fce8d81d7f | ||
|
7ed6ad7254 | ||
|
49ec85b4fa | ||
|
860c880454 | ||
|
ec39158ce8 | ||
|
b926125618 | ||
|
112af14dd5 | ||
|
f2831c875e | ||
|
630cb2a981 | ||
|
dd852138d6 | ||
|
ca42518c1d | ||
|
41c1e30e9b | ||
|
b973c9b473 | ||
|
c79dd88edb | ||
|
40bf479666 | ||
|
59660c4650 | ||
|
6260deec9a | ||
|
26a12fd9ac | ||
|
b64edfc92b | ||
|
ec6faab94b | ||
|
031792c400 | ||
|
0d6a2fa9e7 | ||
|
0983de0692 | ||
|
ec6f185787 | ||
|
4eece9d5ee | ||
|
347715da30 | ||
|
27654be0b5 | ||
|
84cd523d8c | ||
|
ae692bfb3b | ||
|
a016042a9a | ||
|
d53a4f80bf | ||
|
9480a83ddf | ||
|
db8d865193 | ||
|
237fc59ba8 | ||
|
cfe2854740 | ||
|
77c2e27e6c | ||
|
3abb79b0ae | ||
|
cc5a23d4c1 | ||
|
ff66ca9039 | ||
|
0e6a9c54f2 | ||
|
c519a1a9c1 | ||
|
c086d280b9 | ||
|
2d6fa07fd5 | ||
|
12cfc5ecf4 | ||
|
1d0790c0c6 | ||
|
5e535b246a | ||
|
ad4ac5780f | ||
|
3927a5a54a | ||
|
e038b0fcff | ||
|
9f7eab039a | ||
|
233a011db0 | ||
|
f23675a6e4 | ||
|
8cb6ded867 | ||
|
6bab27b56d | ||
|
325ff61910 | ||
|
cf86c9252d | ||
|
5b4001e810 | ||
|
52d41feeaf | ||
|
5b5da2b010 | ||
|
89c0051304 | ||
|
713b0d2b80 | ||
|
5d516bb4a9 | ||
|
7360781a8f | ||
|
16f16486ee | ||
|
ce33d5af9a | ||
|
673be01cdc | ||
|
e475e2d0b1 | ||
|
b289f0928e | ||
|
1f44387665 | ||
|
598625fdaa | ||
|
c6386bb654 | ||
|
5a1ae88561 | ||
|
0ce0fa45aa | ||
|
49420c51f3 | ||
|
25dde3dcf7 | ||
|
4dbc7e0f4b | ||
|
fe612e771b | ||
|
13567b2ae0 | ||
|
7dce13ab4a | ||
|
4b3888751a | ||
|
13750dfa41 | ||
|
0699034db4 | ||
|
2264ca7e14 | ||
|
285ee63ec3 | ||
|
d658acc402 | ||
|
00bec36bed | ||
|
4b364b82f0 | ||
|
80627b9d52 | ||
|
e199951a57 | ||
|
ab64476ae5 | ||
|
45dedc4338 | ||
|
860d4a3841 | ||
|
230a9eea39 | ||
|
17efc775cd | ||
|
c33b2bea09 | ||
|
7c50b9f2eb | ||
|
79f41156e8 | ||
|
abc3c22551 | ||
|
c8f5c9e406 |
@@ -1,10 +1,4 @@
|
||||
apparmor-*
|
||||
cscope.*
|
||||
binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/po/*.mo
|
||||
parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
@@ -19,37 +13,6 @@ parser/parser_version.h
|
||||
parser/parser_yacc.c
|
||||
parser/parser_yacc.h
|
||||
parser/pod2htm*.tmp
|
||||
parser/af_rule.o
|
||||
parser/af_unix.o
|
||||
parser/common_optarg.o
|
||||
parser/dbus.o
|
||||
parser/lib.o
|
||||
parser/libapparmor_re/aare_rules.o
|
||||
parser/libapparmor_re/chfa.o
|
||||
parser/libapparmor_re/expr-tree.o
|
||||
parser/libapparmor_re/hfa.o
|
||||
parser/libapparmor_re/libapparmor_re.a
|
||||
parser/libapparmor_re/parse.o
|
||||
parser/mount.o
|
||||
parser/network.o
|
||||
parser/parser_alias.o
|
||||
parser/parser_common.o
|
||||
parser/parser_include.o
|
||||
parser/parser_interface.o
|
||||
parser/parser_lex.o
|
||||
parser/parser_main.o
|
||||
parser/parser_merge.o
|
||||
parser/parser_misc.o
|
||||
parser/parser_policy.o
|
||||
parser/parser_regex.o
|
||||
parser/parser_symtab.o
|
||||
parser/parser_variable.o
|
||||
parser/parser_yacc.o
|
||||
parser/policy_cache.o
|
||||
parser/profile.o
|
||||
parser/ptrace.o
|
||||
parser/rule.o
|
||||
parser/signal.o
|
||||
parser/*.7
|
||||
parser/*.5
|
||||
parser/*.8
|
||||
@@ -63,8 +26,7 @@ parser/techdoc.aux
|
||||
parser/techdoc.log
|
||||
parser/techdoc.pdf
|
||||
parser/techdoc.toc
|
||||
profiles/apparmor.d/local/*
|
||||
!profiles/apparmor.d/local/README
|
||||
profiles/apparmor.d/local/*.*
|
||||
libraries/libapparmor/Makefile
|
||||
libraries/libapparmor/Makefile.in
|
||||
libraries/libapparmor/aclocal.m4
|
||||
@@ -95,27 +57,17 @@ libraries/libapparmor/src/.deps
|
||||
libraries/libapparmor/src/.libs
|
||||
libraries/libapparmor/src/Makefile
|
||||
libraries/libapparmor/src/Makefile.in
|
||||
libraries/libapparmor/src/PMurHash.lo
|
||||
libraries/libapparmor/src/PMurHash.o
|
||||
libraries/libapparmor/src/af_protos.h
|
||||
libraries/libapparmor/src/change_hat.lo
|
||||
libraries/libapparmor/src/features.lo
|
||||
libraries/libapparmor/src/features.o
|
||||
libraries/libapparmor/src/grammar.lo
|
||||
libraries/libapparmor/src/grammar.o
|
||||
libraries/libapparmor/src/kernel.lo
|
||||
libraries/libapparmor/src/kernel.o
|
||||
libraries/libapparmor/src/kernel_interface.lo
|
||||
libraries/libapparmor/src/kernel_interface.o
|
||||
libraries/libapparmor/src/libaalogparse.lo
|
||||
libraries/libapparmor/src/libaalogparse.o
|
||||
libraries/libapparmor/src/libimmunix_warning.lo
|
||||
libraries/libapparmor/src/policy_cache.lo
|
||||
libraries/libapparmor/src/policy_cache.o
|
||||
libraries/libapparmor/src/private.lo
|
||||
libraries/libapparmor/src/private.o
|
||||
libraries/libapparmor/src/scanner.lo
|
||||
libraries/libapparmor/src/scanner.o
|
||||
libraries/libapparmor/src/libapparmor.pc
|
||||
libraries/libapparmor/src/libapparmor.la
|
||||
libraries/libapparmor/src/libimmunix.la
|
||||
@@ -123,19 +75,7 @@ libraries/libapparmor/src/grammar.c
|
||||
libraries/libapparmor/src/grammar.h
|
||||
libraries/libapparmor/src/scanner.c
|
||||
libraries/libapparmor/src/scanner.h
|
||||
libraries/libapparmor/src/test-suite.log
|
||||
libraries/libapparmor/src/tst_aalogmisc
|
||||
libraries/libapparmor/src/tst_aalogmisc.log
|
||||
libraries/libapparmor/src/tst_aalogmisc.o
|
||||
libraries/libapparmor/src/tst_aalogmisc.trs
|
||||
libraries/libapparmor/src/tst_features
|
||||
libraries/libapparmor/src/tst_features.log
|
||||
libraries/libapparmor/src/tst_features.o
|
||||
libraries/libapparmor/src/tst_features.trs
|
||||
libraries/libapparmor/src/tst_kernel
|
||||
libraries/libapparmor/src/tst_kernel.log
|
||||
libraries/libapparmor/src/tst_kernel.o
|
||||
libraries/libapparmor/src/tst_kernel.trs
|
||||
libraries/libapparmor/swig/Makefile
|
||||
libraries/libapparmor/swig/Makefile.in
|
||||
libraries/libapparmor/swig/perl/LibAppArmor.bs
|
||||
@@ -149,7 +89,6 @@ libraries/libapparmor/swig/perl/MYMETA.json
|
||||
libraries/libapparmor/swig/perl/MYMETA.yml
|
||||
libraries/libapparmor/swig/perl/blib
|
||||
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/build/
|
||||
@@ -159,10 +98,6 @@ libraries/libapparmor/swig/python/Makefile.in
|
||||
libraries/libapparmor/swig/python/setup.py
|
||||
libraries/libapparmor/swig/python/test/Makefile
|
||||
libraries/libapparmor/swig/python/test/Makefile.in
|
||||
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/Makefile
|
||||
libraries/libapparmor/swig/ruby/Makefile.in
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
@@ -180,7 +115,6 @@ libraries/libapparmor/testsuite/lib/Makefile.in
|
||||
libraries/libapparmor/testsuite/libaalogparse.test/Makefile
|
||||
libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
|
||||
libraries/libapparmor/testsuite/test_multi/out
|
||||
libraries/libapparmor/testsuite/test_multi_multi-test_multi.o
|
||||
changehat/mod_apparmor/.libs
|
||||
utils/*.8
|
||||
utils/*.8.html
|
||||
@@ -188,15 +122,6 @@ utils/*.5
|
||||
utils/*.5.html
|
||||
utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
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/access
|
||||
tests/regression/apparmor/changehat
|
||||
tests/regression/apparmor/changehat_fail
|
32
Makefile
32
Makefile
@@ -17,9 +17,12 @@ DIRS=libraries/libapparmor \
|
||||
profiles \
|
||||
tests
|
||||
|
||||
# with conversion to git, we don't export from the remote
|
||||
REPO_URL?=git@gitlab.com:apparmor/apparmor.git
|
||||
REPO_BRANCH?=apparmor-2.11
|
||||
#REPO_URL?=lp:apparmor
|
||||
# --per-file-timestamps is failing over SSH, https://bugs.launchpad.net/bzr/+bug/1257078
|
||||
REPO_URL?=https://code.launchpad.net/~apparmor-dev/apparmor/master
|
||||
# alternate possibilities to export from
|
||||
#REPO_URL=.
|
||||
#REPO_URL="bzr+ssh://bazaar.launchpad.net/~sbeattie/+junk/apparmor-dev/"
|
||||
|
||||
COVERITY_DIR=cov-int
|
||||
RELEASE_DIR=apparmor-${VERSION}
|
||||
@@ -28,9 +31,7 @@ __SETUP_DIR?=.
|
||||
# We create a separate version for tags because git can't handle tags
|
||||
# with embedded ~s in them. No spaces around '-' or they'll get
|
||||
# embedded in ${VERSION}
|
||||
# apparmor version tag format 'vX.Y.ZZ'
|
||||
# apparmor branch name format 'apparmor-X.Y'
|
||||
TAG_VERSION="v$(subst ~,-,${VERSION})"
|
||||
TAG_VERSION=$(subst ~,-,${VERSION})
|
||||
|
||||
# Add exclusion entries arguments for tar here, of the form:
|
||||
# --exclude dir_to_exclude --exclude other_dir
|
||||
@@ -46,27 +47,23 @@ tarball: clean
|
||||
.PHONY: snapshot
|
||||
snapshot: clean
|
||||
$(eval REPO_VERSION:=$(shell $(value REPO_VERSION_CMD)))
|
||||
$(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(shell echo $(REPO_VERSION) | cut -d '-' -f 2-))
|
||||
$(MAKE) export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \
|
||||
$(MAKE) setup __SETUP_DIR=${SNAPSHOT_NAME} && \
|
||||
$(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(REPO_VERSION))
|
||||
make export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \
|
||||
make setup __SETUP_DIR=${SNAPSHOT_NAME} && \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${SNAPSHOT_NAME}.tar.gz ${SNAPSHOT_NAME}
|
||||
|
||||
.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) -- make -C $(SNAPSHOT_NAME)/$(dir);)
|
||||
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
|
||||
|
||||
.PHONY: export_dir
|
||||
export_dir:
|
||||
mkdir $(__EXPORT_DIR)
|
||||
/usr/bin/git archive --prefix=$(__EXPORT_DIR)/ --format tar $(__REPO_VERSION) | tar xv
|
||||
echo "$(REPO_URL) $(REPO_BRANCH) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev
|
||||
/usr/bin/bzr export --per-file-timestamps -r $(__REPO_VERSION) $(__EXPORT_DIR) $(REPO_URL)
|
||||
echo "$(REPO_URL) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -87,4 +84,5 @@ setup:
|
||||
|
||||
.PHONY: tag
|
||||
tag:
|
||||
git tag -m 'AppArmor $(VERSION)' -s $(TAG_VERSION)
|
||||
bzr tag apparmor_${TAG_VERSION}
|
||||
|
||||
|
@@ -1,9 +1,3 @@
|
||||
# AppArmor
|
||||
|
||||
[](https://gitlab.com/apparmor/apparmor/commits/master)
|
||||
[](https://gitlab.com/apparmor/apparmor/pipelines)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/1699)
|
||||
|
||||
------------
|
||||
Introduction
|
||||
------------
|
||||
@@ -23,27 +17,9 @@ library, available under the LGPL license, which allows change_hat(2)
|
||||
and change_profile(2) to be used by non-GPL binaries).
|
||||
|
||||
For more information, you can read the techdoc.pdf (available after
|
||||
building the parser) and by visiting the https://apparmor.net/ web
|
||||
building the parser) and by visiting the http://apparmor.net/ web
|
||||
site.
|
||||
|
||||
----------------
|
||||
Getting in Touch
|
||||
----------------
|
||||
|
||||
Please send all complaints, feature requests, rants about the software,
|
||||
and questions to the
|
||||
[AppArmor mailing list](https://lists.ubuntu.com/mailman/listinfo/apparmor).
|
||||
|
||||
Bug reports can be filed against the AppArmor project on
|
||||
[launchpad](https://bugs.launchpad.net/apparmor) or reported to the mailing
|
||||
list directly for those who wish not to register for an account on
|
||||
launchpad. See the
|
||||
[wiki page](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-bugs)
|
||||
for more information.
|
||||
|
||||
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).
|
||||
|
||||
-------------
|
||||
Source Layout
|
||||
@@ -51,7 +27,6 @@ Source Layout
|
||||
|
||||
AppArmor consists of several different parts:
|
||||
|
||||
```
|
||||
binutils/ source for basic utilities written in compiled languages
|
||||
changehat/ source for using changehat with Apache, PAM and Tomcat
|
||||
common/ common makefile rules
|
||||
@@ -62,7 +37,6 @@ parser/ source for parser/loader and corresponding documentation
|
||||
profiles/ configuration files, reference profiles and abstractions
|
||||
tests/ regression and stress testsuites
|
||||
utils/ high-level utilities for working with AppArmor
|
||||
```
|
||||
|
||||
--------------------------------------
|
||||
Important note on AppArmor kernel code
|
||||
@@ -83,86 +57,60 @@ Building and Installing AppArmor Userspace
|
||||
------------------------------------------
|
||||
|
||||
To build and install AppArmor userspace on your system, build and install in
|
||||
the following order. Some systems may need to export various python-related
|
||||
environment variables to complete the build. For example, before building
|
||||
anything on these systems, use something along the lines of:
|
||||
the following order.
|
||||
|
||||
```
|
||||
$ export PYTHONPATH=$(realpath libraries/libapparmor/swig/python)
|
||||
$ export PYTHON=/usr/bin/python3
|
||||
$ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
$ sh ./autogen.sh
|
||||
$ sh ./configure --prefix=/usr --with-perl --with-python # see below
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
[an additional optional argument to libapparmor's configure is --with-ruby, to
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
Binary Utilities:
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
parser:
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
Utilities:
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
parser:
|
||||
$ cd parser
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
|
||||
Apache mod_apparmor:
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
PAM AppArmor:
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
Profiles:
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
$ make
|
||||
$ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
[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
|
||||
@@ -183,50 +131,38 @@ For details on structure and adding tests, see
|
||||
tests/regression/apparmor/README.
|
||||
|
||||
To run:
|
||||
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make
|
||||
$ sudo make tests
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
|
||||
|
||||
Parser tests
|
||||
------------
|
||||
For details on structure and adding tests, see parser/tst/README.
|
||||
|
||||
To run:
|
||||
|
||||
```
|
||||
$ cd parser/tst
|
||||
$ make
|
||||
$ make tests
|
||||
```
|
||||
|
||||
|
||||
Libapparmor
|
||||
-----------
|
||||
For details on structure and adding tests, see libraries/libapparmor/README.
|
||||
|
||||
```
|
||||
$ cd libraries/libapparmor
|
||||
$ make check
|
||||
```
|
||||
|
||||
Utils
|
||||
-----
|
||||
Tests for the Python utilities exist in the test/ subdirectory.
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make check
|
||||
```
|
||||
|
||||
The aa-decode utility to be tested can be overridden by
|
||||
setting up environment variable APPARMOR_DECODE; e.g.:
|
||||
|
||||
```
|
||||
$ APPARMOR_DECODE=/usr/bin/aa-decode make check
|
||||
```
|
||||
|
||||
Profile checks
|
||||
--------------
|
||||
@@ -234,44 +170,29 @@ A basic consistency check to ensure that the parser and aa-logprof parse
|
||||
successfully the current set of shipped profiles. The system or other
|
||||
parser and logprof can be passed in by overriding the PARSER and LOGPROF
|
||||
variables.
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
$ make && make check
|
||||
```
|
||||
|
||||
Stress Tests
|
||||
------------
|
||||
To run AppArmor stress tests:
|
||||
|
||||
```
|
||||
$ make all
|
||||
```
|
||||
|
||||
Use these:
|
||||
|
||||
```
|
||||
$ ./change_hat
|
||||
$ ./child
|
||||
$ ./kill.sh
|
||||
$ ./open
|
||||
$ ./s.sh
|
||||
```
|
||||
|
||||
Or run all at once:
|
||||
|
||||
```
|
||||
$ ./stress.sh
|
||||
```
|
||||
|
||||
Please note that the above will stress the system so much it may end up
|
||||
invoking the OOM killer.
|
||||
|
||||
To run parser stress tests (requires /usr/bin/ruby):
|
||||
|
||||
```
|
||||
$ ./stress.sh
|
||||
```
|
||||
|
||||
(see stress.sh -h for options)
|
||||
|
||||
@@ -286,10 +207,7 @@ https://scan.coverity.com/download?tab=cxx to obtain a pre-built copy of
|
||||
cov-build.
|
||||
|
||||
To generate a compressed tarball of an intermediate Coverity directory:
|
||||
|
||||
```
|
||||
$ make coverity
|
||||
```
|
||||
|
||||
The compressed tarball is written to
|
||||
apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION>
|
@@ -114,7 +114,7 @@ $(LIBAPPARMOR_A):
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
exit 1; \
|
||||
return 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
|
@@ -56,27 +56,27 @@ Upon exiting, B<aa-enabled> will set its exit status to the following values:
|
||||
|
||||
=over 4
|
||||
|
||||
=item 0:
|
||||
=item B<0>
|
||||
|
||||
if AppArmor is enabled.
|
||||
|
||||
=item 1:
|
||||
=item B<1>
|
||||
|
||||
if AppArmor is not enabled/loaded.
|
||||
|
||||
=item 2:
|
||||
=item B<2>
|
||||
|
||||
intentionally not used as an B<aa-enabled> exit status.
|
||||
|
||||
=item 3:
|
||||
=item B<3>
|
||||
|
||||
if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item 4:
|
||||
=item B<4>
|
||||
|
||||
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
|
||||
|
||||
=item 64:
|
||||
=item B<64>
|
||||
|
||||
if any unexpected error or condition is encountered.
|
||||
|
||||
@@ -89,6 +89,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<https://wiki.apparmor.net>.
|
||||
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -88,6 +88,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
aa-stack(8), aa-namespace(8), apparmor(7), apparmor.d(5), aa_change_profile(3),
|
||||
aa_change_onexec(3) and L<https://wiki.apparmor.net>.
|
||||
aa_change_onexec(3) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -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: 2016-03-20 01:58+0000\n"
|
||||
"Last-Translator: Tobias Bannert <Unknown>\n"
|
||||
"PO-Revision-Date: 2017-03-31 10:44+0000\n"
|
||||
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\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: 2016-03-21 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 17947)\n"
|
||||
"X-Launchpad-Export-Date: 2017-04-05 05:23+0000\n"
|
||||
"X-Generator: Launchpad (build 18335)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
@@ -30,12 +30,12 @@ msgstr ""
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
msgstr "unbekannte oder nicht kompatible Optionen\n"
|
||||
|
||||
#: ../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
|
||||
|
@@ -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: 2016-02-19 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17925)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: en_GB\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: 2016-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -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-03 08:34+0000\n"
|
||||
"Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n"
|
||||
"Last-Translator: Ivo Xavier <ivoxavier.8@gmail.com>\n"
|
||||
"Language-Team: Portuguese <pt@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: 2016-03-04 04:35+0000\n"
|
||||
"X-Generator: Launchpad (build 17936)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: pt\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: 2016-03-30 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 17967)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ru\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -140,6 +140,6 @@ them at L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -42,9 +42,10 @@ 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
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/bzr ] && /usr/bin/bzr version-info --custom --template="{revno}" . 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
|
||||
|
||||
ifndef PYTHON_VERSIONS
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python2 python3)
|
||||
|
@@ -1 +1 @@
|
||||
2.11.2
|
||||
2.11.95
|
||||
|
@@ -138,7 +138,7 @@ 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_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:\nhttp://wiki.apparmor.net/index.php/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."));
|
||||
|
||||
@@ -195,7 +195,7 @@ for my $p (sort keys %helpers) {
|
||||
}
|
||||
|
||||
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(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttp://wiki.apparmor.net/index.php/Profiles\n"));
|
||||
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
|
||||
exit 0;
|
||||
|
||||
|
@@ -0,0 +1,605 @@
|
||||
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
|
||||
|
@@ -0,0 +1,38 @@
|
||||
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
|
||||
|
@@ -0,0 +1,938 @@
|
||||
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
|
||||
|
@@ -0,0 +1,605 @@
|
||||
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
|
||||
|
@@ -0,0 +1,38 @@
|
||||
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
|
||||
|
@@ -0,0 +1,938 @@
|
||||
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
|
||||
|
@@ -0,0 +1,41 @@
|
||||
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
|
||||
|
@@ -0,0 +1,51 @@
|
||||
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
|
||||
|
@@ -0,0 +1,32 @@
|
||||
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
|
||||
|
@@ -0,0 +1,37 @@
|
||||
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
|
||||
|
@@ -0,0 +1,29 @@
|
||||
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
|
||||
|
@@ -0,0 +1,397 @@
|
||||
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
|
||||
|
1051
kernel-patches/v4.13/0007-apparmor-add-mount-mediation.patch
Normal file
1051
kernel-patches/v4.13/0007-apparmor-add-mount-mediation.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
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
|
||||
|
@@ -0,0 +1,63 @@
|
||||
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
|
||||
|
@@ -0,0 +1,219 @@
|
||||
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
|
||||
|
@@ -0,0 +1,78 @@
|
||||
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
@@ -0,0 +1,194 @@
|
||||
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
|
||||
|
@@ -0,0 +1,60 @@
|
||||
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
|
||||
|
@@ -0,0 +1,36 @@
|
||||
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
|
||||
|
@@ -0,0 +1,39 @@
|
||||
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
5
kernel-patches/v4.13/README
Normal file
5
kernel-patches/v4.13/README
Normal file
@@ -0,0 +1,5 @@
|
||||
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
4
kernel-patches/v4.14/README
Normal file
4
kernel-patches/v4.14/README
Normal file
@@ -0,0 +1,4 @@
|
||||
This series is based on what is currently in linux-next scheduled for
|
||||
inclusion in 4.14
|
||||
|
||||
af_unix-mediation is the last remaining patch that is out of tree
|
@@ -0,0 +1,603 @@
|
||||
From 269384ead6a3c82ac31fd3778e899ccc6a54358e 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 | 44 ++++++++++
|
||||
security/apparmor/include/policy.h | 3 +
|
||||
security/apparmor/lsm.c | 112 +++++++++++++++++++++++++
|
||||
security/apparmor/net.c | 162 +++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 46 +++++++++++
|
||||
10 files changed, 414 insertions(+), 2 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 d693df874818..5dbb72f46452 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 sid.o file.o
|
||||
+ resource.o sid.o file.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 729e595119ed..181d961e6d58 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -807,6 +807,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 ba3dfd17f23f..5d3c419b17d9 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -125,6 +125,10 @@ struct apparmor_audit_data {
|
||||
u32 denied;
|
||||
kuid_t ouid;
|
||||
} fs;
|
||||
+ 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..cb8a12109b7a
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -0,0 +1,44 @@
|
||||
+/*
|
||||
+ * 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[];
|
||||
+
|
||||
+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk);
|
||||
+extern int aa_revalidate_sk(int 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 52275f040a5f..4fc4dacc1101 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "capability.h"
|
||||
#include "domain.h"
|
||||
#include "file.h"
|
||||
+#include "net.h"
|
||||
#include "resource.h"
|
||||
|
||||
extern const char *const aa_profile_mode_names[];
|
||||
@@ -176,6 +177,7 @@ struct aa_replacedby {
|
||||
* @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
|
||||
@@ -217,6 +219,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;
|
||||
|
||||
unsigned char *hash;
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 41b8cb115801..d96b5f7c1912 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -32,6 +32,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/procattr.h"
|
||||
@@ -584,6 +585,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_SOCK_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),
|
||||
@@ -613,6 +712,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..003dd18c61a5
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -0,0 +1,162 @@
|
||||
+/*
|
||||
+ * 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[sa->aad->net.type]) {
|
||||
+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
|
||||
+ }
|
||||
+ audit_log_format(ab, " protocol=%d", sa->aad->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, int op, u16 family, int type,
|
||||
+ int protocol, struct sock *sk, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ struct common_audit_data sa;
|
||||
+ struct apparmor_audit_data aad = { };
|
||||
+ struct lsm_network_audit net = { };
|
||||
+ if (sk) {
|
||||
+ sa.type = LSM_AUDIT_DATA_NET;
|
||||
+ } else {
|
||||
+ sa.type = LSM_AUDIT_DATA_NONE;
|
||||
+ }
|
||||
+ /* todo fill in socket addr info */
|
||||
+ sa.aad = &aad;
|
||||
+ sa.u.net = &net;
|
||||
+ sa.aad->op = op,
|
||||
+ sa.u.net->family = family;
|
||||
+ sa.u.net->sk = sk;
|
||||
+ sa.aad->net.type = type;
|
||||
+ sa.aad->net.protocol = protocol;
|
||||
+ sa.aad->error = error;
|
||||
+
|
||||
+ if (likely(!sa.aad->error)) {
|
||||
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
|
||||
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
|
||||
+ !(1 << sa.aad->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 << sa.aad->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 : sa.aad->error;
|
||||
+ }
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, GFP_KERNEL, &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(int 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(int 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 179e68d7dc5f..f1a8541760e8 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -603,6 +603,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 138120698f83..7dc15ff91299 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -193,6 +193,19 @@ fail:
|
||||
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)) {
|
||||
@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
const char *name = NULL;
|
||||
+ size_t size = 0;
|
||||
int i, error = -EPROTO;
|
||||
kernel_cap_t tmpcap;
|
||||
u32 tmp;
|
||||
@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
|
||||
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
|
||||
|
@@ -0,0 +1,38 @@
|
||||
From 88ba6f37ed824ca24901fca7e399168db5e46f12 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 003dd18c61a5..6e6e5c981006 100644
|
||||
--- a/security/apparmor/net.c
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
|
||||
} else {
|
||||
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
u16 kill_mask = 0;
|
||||
- u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
|
||||
+ u16 denied = (1 << sa.aad->net.type);
|
||||
|
||||
if (denied & kill_mask)
|
||||
audit_type = AUDIT_APPARMOR_KILL;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -0,0 +1,962 @@
|
||||
From 6556d6523f74e90a801503d28e7b8dcc5caa6a1b 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 | 15 +-
|
||||
security/apparmor/audit.c | 4 +
|
||||
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 | 620 +++++++++++++++++++++++++++++++++++
|
||||
10 files changed, 769 insertions(+), 4 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 5dbb72f46452..89b344541868 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 sid.o file.o net.o
|
||||
+ resource.o sid.o file.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 181d961e6d58..5fb67f60bace 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
|
||||
|
||||
static struct aa_fs_entry aa_fs_entry_policy[] = {
|
||||
AA_FS_FILE_BOOLEAN("set_load", 1),
|
||||
- {}
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+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[] = {
|
||||
@@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
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/audit.c b/security/apparmor/audit.c
|
||||
index 3a7f1da1425e..c2a8b8ac38a7 100644
|
||||
--- a/security/apparmor/audit.c
|
||||
+++ b/security/apparmor/audit.c
|
||||
@@ -44,6 +44,10 @@ const char *const op_table[] = {
|
||||
"file_mmap",
|
||||
"file_mprotect",
|
||||
|
||||
+ "pivotroot",
|
||||
+ "mount",
|
||||
+ "umount",
|
||||
+
|
||||
"create",
|
||||
"post_create",
|
||||
"bind",
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index fc3036b34e51..f2a83b4430db 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -236,7 +236,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_namespace *ns = profile->ns;
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index 5d721e990876..b57da7b9f8bd 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -30,8 +30,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 5d3c419b17d9..b9f1d57984ca 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -72,6 +72,10 @@ enum aa_ops {
|
||||
OP_FMMAP,
|
||||
OP_FMPROT,
|
||||
|
||||
+ OP_PIVOTROOT,
|
||||
+ OP_MOUNT,
|
||||
+ OP_UMOUNT,
|
||||
+
|
||||
OP_CREATE,
|
||||
OP_POST_CREATE,
|
||||
OP_BIND,
|
||||
@@ -120,6 +124,13 @@ struct apparmor_audit_data {
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
struct {
|
||||
+ const char *src_name;
|
||||
+ const char *type;
|
||||
+ const char *trans;
|
||||
+ const char *data;
|
||||
+ unsigned long flags;
|
||||
+ } mnt;
|
||||
+ struct {
|
||||
const char *target;
|
||||
u32 request;
|
||||
u32 denied;
|
||||
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
|
||||
index de04464f0a3f..a3f70c58ef3d 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 d96b5f7c1912..5ff9984cba5a 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/procattr.h"
|
||||
+#include "include/mount.h"
|
||||
|
||||
/* Flag indicating whether initialization completed */
|
||||
int apparmor_initialized __initdata;
|
||||
@@ -469,6 +470,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)
|
||||
{
|
||||
@@ -689,6 +745,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..9cf9170b4976
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/mount.c
|
||||
@@ -0,0 +1,620 @@
|
||||
+/*
|
||||
+ * 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 (sa->aad->mnt.type) {
|
||||
+ audit_log_format(ab, " fstype=");
|
||||
+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
|
||||
+ }
|
||||
+ if (sa->aad->mnt.src_name) {
|
||||
+ audit_log_format(ab, " srcname=");
|
||||
+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
|
||||
+ }
|
||||
+ if (sa->aad->mnt.trans) {
|
||||
+ audit_log_format(ab, " trans=");
|
||||
+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
|
||||
+ }
|
||||
+ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
|
||||
+ audit_log_format(ab, " flags=\"");
|
||||
+ audit_mnt_flags(ab, sa->aad->mnt.flags);
|
||||
+ audit_log_format(ab, "\"");
|
||||
+ }
|
||||
+ if (sa->aad->mnt.data) {
|
||||
+ audit_log_format(ab, " options=");
|
||||
+ audit_log_untrustedstring(ab, sa->aad->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, int 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;
|
||||
+ struct common_audit_data sa = { };
|
||||
+ struct apparmor_audit_data aad = { };
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ sa.type = LSM_AUDIT_DATA_NONE;
|
||||
+ sa.aad = &aad;
|
||||
+ sa.aad->op = op;
|
||||
+ sa.aad->name = name;
|
||||
+ sa.aad->mnt.src_name = src_name;
|
||||
+ sa.aad->mnt.type = type;
|
||||
+ sa.aad->mnt.trans = trans;
|
||||
+ sa.aad->mnt.flags = flags;
|
||||
+ if (data && (perms->audit & AA_AUDIT_DATA))
|
||||
+ sa.aad->mnt.data = data;
|
||||
+ sa.aad->info = info;
|
||||
+ sa.aad->error = error;
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, gfp, &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 const *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
|
||||
|
@@ -257,6 +257,6 @@ should be used.
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
|
||||
aa_getcon(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -204,6 +204,6 @@ separate processes should be used.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -143,6 +143,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
openat(2) and L<https://wiki.apparmor.net>.
|
||||
openat(2) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -115,6 +115,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -132,6 +132,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
|
||||
aa_splitcon(3) and L<https://wiki.apparmor.net>.
|
||||
aa_splitcon(3) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -157,6 +157,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
aa_features(3), openat(2) and L<https://wiki.apparmor.net>.
|
||||
aa_features(3), openat(2) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -120,6 +120,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
aa_features(3), aa_kernel_interface(3), openat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -128,6 +128,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_getcon(2), aa_splitcon(3)
|
||||
and L<https://wiki.apparmor.net>.
|
||||
and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -67,6 +67,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
aa_getcon(2) and L<https://wiki.apparmor.net>.
|
||||
aa_getcon(2) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -216,6 +216,6 @@ separate processes should be used.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
|
||||
aa_getcon(2) and L<https://wiki.apparmor.net>.
|
||||
aa_getcon(2) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -22,7 +22,9 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class of public mediation types in the AppArmor policy db
|
||||
@@ -66,7 +68,7 @@ extern int aa_is_enabled(void);
|
||||
extern int aa_find_mountpoint(char **mnt);
|
||||
|
||||
/* Prototypes for self directed domain transitions
|
||||
* see <https://apparmor.net>
|
||||
* see <http://apparmor.net>
|
||||
* Please see the change_hat(2) manpage for information.
|
||||
*/
|
||||
|
||||
@@ -191,6 +193,8 @@ extern int aa_policy_cache_remove(int dirfd, const char *path);
|
||||
extern int aa_policy_cache_replace_all(aa_policy_cache *policy_cache,
|
||||
aa_kernel_interface *kernel_interface);
|
||||
|
||||
__END_DECLS
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* sys/apparmor.h */
|
||||
|
@@ -20,7 +20,9 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int _aa_is_blacklisted(const char *name);
|
||||
|
||||
@@ -33,6 +35,8 @@ int _aa_asprintf(char **strp, const char *fmt, ...);
|
||||
int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
int (* cb)(int, const char *, struct stat *, void *));
|
||||
|
||||
__END_DECLS
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* sys/apparmor_private.h */
|
||||
|
@@ -27,7 +27,7 @@ INCLUDES = $(all_includes)
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 5
|
||||
AA_LIB_REVISION = 2
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 4
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
@@ -12,7 +12,6 @@ LibAppArmor.pm: libapparmor_wrap.c
|
||||
|
||||
Makefile.perl: Makefile.PL LibAppArmor.pm
|
||||
$(PERL) $< PREFIX=$(prefix) MAKEFILE=$@
|
||||
sed -ie 's/LD_RUN_PATH="\x24(LD_RUN_PATH)"//g' Makefile.perl
|
||||
sed -ie 's/^LD_RUN_PATH.*//g' Makefile.perl
|
||||
|
||||
LibAppArmor.so: libapparmor_wrap.c Makefile.perl
|
||||
|
@@ -5,7 +5,7 @@ setup(name = 'LibAppArmor',
|
||||
version = '@VERSION@',
|
||||
author = 'AppArmor Dev Team',
|
||||
author_email = 'apparmor@lists.ubuntu.com',
|
||||
url = 'https://wiki.apparmor.net',
|
||||
url = 'http://wiki.apparmor.net',
|
||||
description = 'AppArmor python bindings',
|
||||
download_url = 'https://launchpad.net/apparmor/+download',
|
||||
package_dir = {'LibAppArmor': '@srcdir@'},
|
||||
|
@@ -27,9 +27,9 @@ INSTALL_CONFDIR=${DESTDIR}${CONFDIR}
|
||||
LOCALEDIR=/usr/share/locale
|
||||
MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 subdomain.conf.5
|
||||
|
||||
YACC := bison
|
||||
YACC := /usr/bin/bison
|
||||
YFLAGS := -d
|
||||
LEX := flex
|
||||
LEX := /usr/bin/flex
|
||||
LEXFLAGS = -B -v
|
||||
WARNINGS = -Wall
|
||||
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
|
||||
@@ -179,7 +179,7 @@ $(LIBAPPARMOR_A):
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
exit 1; \
|
||||
return 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
|
@@ -2,6 +2,19 @@ The apparmor_parser allows you to add, replace, and remove AppArmor
|
||||
policy through the use of command line options. The default is to add.
|
||||
`apparmor_parser --help` shows what the command line options are.
|
||||
|
||||
You can also find more information at https://wiki.apparmor.net
|
||||
You can also find more information at http://wiki.apparmor.net
|
||||
|
||||
Please send all complaints, feature requests, rants about the software,
|
||||
and questions to the apparmor@lists.ubuntu.com mailing list. Bug
|
||||
reports can be filed against the AppArmor project on launchpad.net at
|
||||
https://launchpad.net/apparmor or reported to the mailing list directly
|
||||
for those who wish not to register for an account on launchpad.
|
||||
|
||||
Security issues can be filed as security bugs on launchpad
|
||||
or directed to security@ubuntu.com. We will attempt to
|
||||
conform to the RFP vulnerability disclosure protocol:
|
||||
http://www.wiretrip.net/rfp/policy.html
|
||||
|
||||
Thanks.
|
||||
|
||||
-- The AppArmor development team
|
||||
|
@@ -55,7 +55,7 @@ B<VARIABLE> = '@{' I<ALPHA> [ ( I<ALPHANUMERIC> | '_' ) ... ] '}'
|
||||
|
||||
B<ALIAS RULE> = 'alias' I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ','
|
||||
|
||||
B<INCLUDE> = ( '#include' | 'include' ) [ 'if exists' ] ( I<ABS PATH> | I<MAGIC PATH> )
|
||||
B<INCLUDE> = '#include' ( I<ABS PATH> | I<MAGIC PATH> )
|
||||
|
||||
B<ABS PATH> = '"' path '"' (the path is passed to open(2))
|
||||
|
||||
@@ -1414,17 +1414,13 @@ rules into a rule block.
|
||||
|
||||
=head2 #include mechanism
|
||||
|
||||
AppArmor provides an easy abstraction mechanism to group common
|
||||
AppArmor provides an easy abstraction mechanism to group common file
|
||||
access requirements; this abstraction is an extremely flexible way to
|
||||
grant site-specific rights and makes writing new AppArmor profiles very
|
||||
simple by assembling the needed building blocks for any given program.
|
||||
|
||||
The use of '#include' is modelled directly after cpp(1); its use will
|
||||
replace the '#include' statement with the specified file's contents.
|
||||
The leading '#' is optional, and the '#include' keyword can be followed
|
||||
by an option conditional 'if exists' that specifies profile compilation
|
||||
should continue if the specified file or directory is not found.
|
||||
|
||||
B<#include "/absolute/path"> specifies that F</absolute/path> should be
|
||||
used. B<#include "relative/path"> specifies that F<relative/path> should
|
||||
be used, where the path is relative to the current working directory.
|
||||
@@ -1611,6 +1607,6 @@ negative values match when specifying one or the other. Eg, 'rw' matches when
|
||||
|
||||
apparmor(7), apparmor_parser(8), aa-complain(1),
|
||||
aa-enforce(1), aa_change_hat(2), mod_apparmor(5), and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -70,12 +70,9 @@ with B<.> (except for the root B</>) so profiles are easier to manage
|
||||
(e.g. the F</usr/sbin/nscd> profile would be named F<usr.sbin.nscd>).
|
||||
|
||||
Profiles are applied to a process at exec(3) time (as seen through the
|
||||
execve(2) system call): once a profile is loaded for a program, that
|
||||
program will be confined on the next exec(3). If a process is already
|
||||
running under a profile, when one replaces that profile in the kernel,
|
||||
the updated profile is applied immediately to that process.
|
||||
On the other hand, a process that is already running unconfined cannot
|
||||
be confined.
|
||||
execve(2) system call); an already running process cannot be confined.
|
||||
However, once a profile is loaded for a program, that program will be
|
||||
confined on the next exec(3).
|
||||
|
||||
AppArmor supports the Linux kernel's securityfs filesystem, and makes
|
||||
available the list of the profiles currently loaded; to mount the
|
||||
@@ -165,6 +162,6 @@ apparmor_parser(8), aa_change_hat(2), apparmor.d(5),
|
||||
subdomain.conf(5), aa-autodep(1), clean(1),
|
||||
auditd(8),
|
||||
aa-unconfined(8), aa-enforce(1), aa-complain(1), and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -46,7 +46,7 @@ program. The B<profiles> may be specified by file name or a directory
|
||||
name containing a set of profiles. If a directory is specified then the
|
||||
B<apparmor_parser> will try to do a profile load for each file in the
|
||||
directory that is not a dot file, or explicitly black listed (*.dpkg-new,
|
||||
*.dpkg-old, *.dpkg-dist, *-dpkg-bak, *.rpmnew, *.rpmsave, *orig, *.rej,
|
||||
*.dpkg-old, *.dpkg-dist, *-dpkg-bak, *.repnew, *.rpmsave, *orig, *.rej,
|
||||
*~). The B<apparmor_parser> will fall back to taking input from standard
|
||||
input if a profile or directory is not supplied.
|
||||
|
||||
@@ -376,6 +376,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), subdomain.conf(5), aa_change_hat(2), and
|
||||
L<https://wiki.apparmor.net>.
|
||||
L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
|
@@ -144,7 +144,7 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void include_filename(char *filename, int search, bool if_exists)
|
||||
void include_filename(char *filename, int search)
|
||||
{
|
||||
FILE *include_file = NULL;
|
||||
struct stat my_stat;
|
||||
@@ -161,12 +161,9 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
include_file = fopen(fullpath, "r");
|
||||
}
|
||||
|
||||
if (!include_file) {
|
||||
if (if_exists)
|
||||
return;
|
||||
if (!include_file)
|
||||
yyerror(_("Could not open '%s'"),
|
||||
fullpath ? fullpath: filename);
|
||||
}
|
||||
|
||||
if (fstat(fileno(include_file), &my_stat))
|
||||
yyerror(_("fstat failed for '%s'"), fullpath);
|
||||
@@ -203,7 +200,7 @@ MODES {MODE_CHARS}+
|
||||
WS [[:blank:]]
|
||||
NUMBER [[:digit:]]+
|
||||
|
||||
ID_CHARS [^ \t\r\n"!,]
|
||||
ID_CHARS [^ \t\n"!,]
|
||||
ID {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,)
|
||||
IDS {ID}+
|
||||
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
|
||||
@@ -260,8 +257,6 @@ LT_EQUAL <=
|
||||
%x UNIX_MODE
|
||||
%x CHANGE_PROFILE_MODE
|
||||
%x INCLUDE
|
||||
%x INCLUDE_EXISTS
|
||||
%x ABI_MODE
|
||||
|
||||
%%
|
||||
|
||||
@@ -274,59 +269,21 @@ LT_EQUAL <=
|
||||
}
|
||||
%}
|
||||
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
|
||||
}
|
||||
|
||||
<INCLUDE_EXISTS>{
|
||||
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */
|
||||
autofree char *filename = strndup(yytext, yyleng - 1);
|
||||
include_filename(filename + 1, *filename == '<', true);
|
||||
POP_NODUMP();
|
||||
}
|
||||
|
||||
(\<{QUOTED_ID}\>) { /* <"filename"> */
|
||||
autofree char *filename = strndup(yytext, yyleng - 2);
|
||||
include_filename(filename + 2, true, true);
|
||||
POP_NODUMP();
|
||||
}
|
||||
|
||||
({IDS}|{QUOTED_ID}) { /* filename */
|
||||
include_filename(yytext, 0, true);
|
||||
POP_NODUMP();
|
||||
}
|
||||
}
|
||||
|
||||
<INCLUDE>{
|
||||
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */
|
||||
(\<([^\> \t\n]+)\>|\"([^\" \t\n]+)\") { /* <filename> */
|
||||
autofree char *filename = strndup(yytext, yyleng - 1);
|
||||
include_filename(filename + 1, *filename == '<', false);
|
||||
include_filename(filename + 1, *filename == '<');
|
||||
POP_NODUMP();
|
||||
}
|
||||
|
||||
(\<{QUOTED_ID}\>) { /* <"filename"> */
|
||||
autofree char *filename = strndup(yytext, yyleng - 2);
|
||||
include_filename(filename + 2, true, false);
|
||||
[^\<\>\" \t\n]+ { /* filename */
|
||||
include_filename(yytext, 0);
|
||||
POP_NODUMP();
|
||||
}
|
||||
|
||||
({IDS}|{QUOTED_ID}) { /* filename */
|
||||
include_filename(yytext, 0, false);
|
||||
POP_NODUMP();
|
||||
}
|
||||
}
|
||||
|
||||
<ABI_MODE>{
|
||||
(\<(([^"\>\t\r\n]+)|{QUOTED_ID})\>|{QUOTED_ID}|{IDS}) { /* <filename> | <"filename"> | "filename" | filename */
|
||||
int lt = *yytext == '<' ? 1 : 0;
|
||||
char *filename = processid(yytext + lt, yyleng - lt*2);
|
||||
bool exists = YYSTATE == INCLUDE_EXISTS;
|
||||
|
||||
if (!filename)
|
||||
yyerror(_("Failed to process filename\n"));
|
||||
yylval.id = filename;
|
||||
POP_AND_RETURN(TOK_ID);
|
||||
}
|
||||
}
|
||||
|
||||
<<EOF>> {
|
||||
@@ -570,20 +527,6 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
#include{WS}+if{WS}+exists/{WS}.*\r?\n {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
yy_push_state(INCLUDE_EXISTS);
|
||||
}
|
||||
|
||||
include{WS}+if{WS}+exists/{WS} {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
yy_push_state(INCLUDE_EXISTS);
|
||||
}
|
||||
|
||||
#include/.*\r?\n {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
@@ -680,9 +623,6 @@ include/{WS} {
|
||||
case TOK_UNIX:
|
||||
state = UNIX_MODE;
|
||||
break;
|
||||
case TOK_ABI:
|
||||
state = ABI_MODE;
|
||||
break;
|
||||
default: /* nothing */
|
||||
break;
|
||||
}
|
||||
@@ -735,6 +675,4 @@ unordered_map<int, string> state_names = {
|
||||
STATE_TABLE_ENT(UNIX_MODE),
|
||||
STATE_TABLE_ENT(CHANGE_PROFILE_MODE),
|
||||
STATE_TABLE_ENT(INCLUDE),
|
||||
STATE_TABLE_ENT(INCLUDE_EXISTS),
|
||||
STATE_TABLE_ENT(ABI_MODE),
|
||||
};
|
||||
|
@@ -759,7 +759,6 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
if (write_cache)
|
||||
pwarn("%s: cannot use or update cache, disable, or force-complain via stdin\n", progname);
|
||||
}
|
||||
|
||||
@@ -1125,7 +1124,7 @@ int main(int argc, char *argv[])
|
||||
retval = aa_policy_cache_new(&policy_cache, features,
|
||||
AT_FDCWD, cacheloc, max_caches);
|
||||
if (retval) {
|
||||
if (errno != ENOENT && errno != EEXIST && errno != EROFS) {
|
||||
if (errno != ENOENT && errno != EEXIST) {
|
||||
PERROR(_("Failed setting up policy cache (%s): %s\n"),
|
||||
cacheloc, strerror(errno));
|
||||
return 1;
|
||||
|
@@ -111,7 +111,6 @@ static struct keyword_table keyword_table[] = {
|
||||
{"trace", TOK_TRACE},
|
||||
{"tracedby", TOK_TRACEDBY},
|
||||
{"readby", TOK_READBY},
|
||||
{"abi", TOK_ABI},
|
||||
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
@@ -125,7 +124,9 @@ static struct keyword_table rlimit_table[] = {
|
||||
{"core", RLIMIT_CORE},
|
||||
{"rss", RLIMIT_RSS},
|
||||
{"nofile", RLIMIT_NOFILE},
|
||||
#ifdef RLIMIT_OFILE
|
||||
{"ofile", RLIMIT_OFILE},
|
||||
#endif
|
||||
{"as", RLIMIT_AS},
|
||||
{"nproc", RLIMIT_NPROC},
|
||||
{"memlock", RLIMIT_MEMLOCK},
|
||||
|
@@ -152,7 +152,6 @@ void add_local_entry(Profile *prof);
|
||||
%token TOK_TRACE
|
||||
%token TOK_TRACEDBY
|
||||
%token TOK_READBY
|
||||
%token TOK_ABI
|
||||
|
||||
/* rlimits */
|
||||
%token TOK_RLIMIT
|
||||
@@ -401,7 +400,6 @@ hat: hat_start profile_base
|
||||
preamble: { /* nothing */ }
|
||||
| preamble alias { /* nothing */ };
|
||||
| preamble varassign { /* nothing */ };
|
||||
| preamble abi_rule { /* nothing */ };
|
||||
|
||||
alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
@@ -617,8 +615,6 @@ rules: { /* nothing */
|
||||
$$ = prof;
|
||||
};
|
||||
|
||||
rules: rules abi_rule { /* nothing */ }
|
||||
|
||||
rules: rules opt_prefix rule
|
||||
{
|
||||
PDEBUG("matched: rules rule\n");
|
||||
@@ -906,6 +902,7 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
|
||||
pwarn(_("RLIMIT 'cpu' no units specified using default units of seconds\n"));
|
||||
value = tmp;
|
||||
break;
|
||||
#ifdef RLIMIT_RTTIME
|
||||
case RLIMIT_RTTIME:
|
||||
/* RTTIME is measured in microseconds */
|
||||
if (!end || $6 == end || tmp < 0)
|
||||
@@ -917,6 +914,7 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
|
||||
pwarn(_("RLIMIT 'rttime' no units specified using default units of microseconds\n"));
|
||||
value = tmp;
|
||||
break;
|
||||
#endif
|
||||
case RLIMIT_NOFILE:
|
||||
case RLIMIT_NPROC:
|
||||
case RLIMIT_LOCKS:
|
||||
@@ -1067,12 +1065,6 @@ opt_named_transition: { /* nothing */ $$ = NULL; }
|
||||
rule: file_rule { $$ = $1; }
|
||||
| link_rule { $$ = $1; }
|
||||
|
||||
abi_rule: TOK_ABI TOK_ID TOK_END_OF_RULE
|
||||
{
|
||||
pwarn(_("%s: Profile abi not supported, falling back to system abi.\n"), progname);
|
||||
free($2);
|
||||
};
|
||||
|
||||
opt_exec_mode: { /* nothing */ $$ = EXEC_MODE_EMPTY; }
|
||||
| TOK_UNSAFE { $$ = EXEC_MODE_UNSAFE; };
|
||||
| TOK_SAFE { $$ = EXEC_MODE_SAFE; };
|
||||
|
@@ -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: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: af\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ar\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -15,8 +15,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: bg\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -9,8 +9,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: bn\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: bs\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ca\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ce\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: cs\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: cy\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -16,8 +16,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: da\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2014-09-13 00:11-0700\n"
|
||||
"PO-Revision-Date: 2015-09-05 20:55+0000\n"
|
||||
"Last-Translator: Tobias Bannert <Unknown>\n"
|
||||
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
|
||||
"Language-Team: Novell Language <language@novell.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -18,8 +18,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: el\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: en_AU\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: en_CA\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -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: 2016-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: en_GB\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: es\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -15,8 +15,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: et\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -22,8 +22,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: fi\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-04-29 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 17995)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: fr\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -18,8 +18,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: gl\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -9,8 +9,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: gu\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -13,8 +13,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: he\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -11,8 +11,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: hi\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -17,8 +17,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: hr\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -24,8 +24,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: hu\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -15,8 +15,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-03-30 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 17967)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: it\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ja\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -15,8 +15,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ka\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -13,8 +13,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: km\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
@@ -12,8 +12,8 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ko\n"
|
||||
|
||||
#: ../parser_include.c:113
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user