periodic merge from apparmor trunk

This commit is contained in:
Steve Beattie 2015-07-08 06:44:56 -07:00
commit 0e3b8d8fd5
651 changed files with 14712 additions and 1599 deletions

View file

@ -167,3 +167,4 @@ tests/regression/apparmor/unlink
tests/regression/apparmor/xattrs
tests/regression/apparmor/coredump
**/__pycache__/
*.orig

View file

@ -53,7 +53,7 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
AA_LINK_FLAGS = -L$(LIBAPPARMOR_PATH)
AA_LDLIBS = -lapparmor
endif
EXTRA_CFLAGS=$(CFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS)
LIBS=-lpam $(AA_LDLIBS)
OBJECTS=${NAME}.o get_options.o

View file

@ -5,9 +5,9 @@ PODCHECKER = podchecker
if ENABLE_MAN_PAGES
man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2 aa_find_mountpoint.2
man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2 aa_find_mountpoint.2 aa_splitcon.3 aa_query_label.2 aa_features.3 aa_kernel_interface.3 aa_policy_cache.3
PODS = $(subst .2,.pod,$(man_MANS))
PODS = $(subst .2,.pod,$(man_MANS)) $(subst .3,.pod,$(man_MANS))
EXTRA_DIST = $(man_MANS) $(PODS)
@ -23,4 +23,13 @@ CLEANFILES = $(man_MANS)
--stderr \
$< > $@
%.3: %.pod
$(PODCHECKER) -warnings -warnings $<
$(POD2MAN) \
--section=3 \
--release="AppArmor $(VERSION)" \
--center="AppArmor" \
--stderr \
$< > $@
endif

View file

@ -0,0 +1,148 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd.
# essentially adhere to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa_features - an opaque object representing a set of AppArmor kernel features
aa_features_new - create a new aa_features object based on a path
aa_features_new_from_string - create a new aa_features object based on a string
aa_features_new_from_kernel - create a new aa_features object based on the current kernel
aa_features_ref - increments the ref count of an aa_features object
aa_features_unref - decrements the ref count and frees the aa_features object when 0
aa_features_write_to_file - write a string representation of an aa_features object to a file
aa_features_is_equal - equality test for two aa_features objects
aa_features_supports - provides aa_features object support status
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
B<typedef struct aa_features aa_features;>
B<int aa_features_new(aa_features **features, int dirfd, const char *path);>
B<int aa_features_new_from_string(aa_features **features, const char *string, size_t size);>
B<int aa_features_new_from_kernel(aa_features **features);>
B<aa_features *aa_features_ref(aa_features *features);>
B<void aa_features_unref(aa_features *features);>
B<int aa_features_write_to_file(aa_features *features, int dirfd, const char *path);>
B<bool aa_features_is_equal(aa_features *features1, aa_features *features2);>
B<bool aa_features_supports(aa_features *features, const char *str);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
The I<aa_features> object contains information about the AppArmor features
supported by a kernel. The feature support information is based upon the files
AppArmor represents in securityfs, which is typically found at
/sys/kernel/security/apparmor/features/. That information may be parsed and
turned into a string or flat file in order to represent a set of features of a
kernel that is not currently running.
The aa_features_new() function creates an I<aa_features> object based upon a
directory file descriptor and path. The I<path> can point to a file or
directory. See the openat(2) man page for examples of I<dirfd> and I<path>. The
allocated I<features> object must be freed using aa_features_unref().
The aa_features_new_from_string() function is similar except that it accepts a
NUL-terminated string representation of the AppArmor features as the I<string>
argument. The length of the features string, not counting the NUL-terminator,
must be specified as the I<size> argument. The allocated I<features> object
must be freed using aa_features_unref().
The aa_features_new_from_kernel() function creates an I<aa_features> object
from the current running kernel. The allocated I<features> object must be freed
using aa_features_unref().
aa_features_ref() increments the reference count on the I<features> object.
aa_features_unref() decrements the reference count on the I<features> object
and releases all corresponding resources when the reference count reaches zero.
The aa_features_write_to_file() function writes a string representation of the
I<features> object to the file specified by the I<dirfd> and I<path>
combination.
aa_features_is_equal() can be used to detect if the I<features1> and
I<features2> objects are equal. The definition of equality is private to
libapparmor and may be changed in ways that do not break backward
compatibility.
The aa_features_supports() function can be used to query the I<features> object
to determine if a feature is supported. The I<str> argument should be equal to
the path, relative to the "apparmor/features/" directory of securityfs, of the
feature to query. For example, to test if policy version 6 is supported, I<str>
would be "policy/versions/v6".
=head1 RETURN VALUE
The aa_features_new() family of functions return 0 on success and I<*features>
will point to an I<aa_features> object that must be freed by
aa_features_unref(). -1 is returned on error, with errno set appropriately, and
I<*features> will be set to NULL.
aa_features_ref() returns the value of I<features>.
aa_features_write_to_file() returns 0 on success. -1 is returned on error, with
errno set appropriately.
aa_features_is_equal() returns true if I<features1> and I<features2> are equal
and false if they are not equal.
aa_features_supports() returns true if the feature represented by I<str> is
supported and false if it is not supported.
=head1 ERRORS
The errno value will be set according to the underlying error in the
I<aa_features> family of functions that return -1 on error.
=head1 NOTES
All aa_features functions described above are present in libapparmor version
2.10 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
openat(2) and L<http://wiki.apparmor.net>.
=cut

View file

@ -131,7 +131,7 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2) and
L<http://wiki.apparmor.net>.
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
aa_splitcon(3) and L<http://wiki.apparmor.net>.
=cut

View file

@ -0,0 +1,162 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd.
# essentially adhere to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa_kernel_interface - an opaque object representing the AppArmor kernel interface for policy loading, replacing, and removing
aa_kernel_interface_new - create a new aa_kernel_interface object from an optional path
aa_kernel_interface_ref - increments the ref count of an aa_kernel_interface object
aa_kernel_interface_unref - decrements the ref count and frees the aa_kernel_interface object when 0
aa_kernel_interface_load_policy - load a policy from a buffer into the kernel
aa_kernel_interface_load_policy_from_file - load a policy from a file into the kernel
aa_kernel_interface_load_policy_from_fd - load a policy from a file descriptor into the kernel
aa_kernel_interface_replace_policy - replace a policy in the kernel with a policy from a buffer
aa_kernel_interface_replace_policy_from_file - replace a policy in the kernel with a policy from a file
aa_kernel_interface_replace_policy_from_fd - replace a policy in the kernel with a policy from a file descriptor
aa_kernel_interface_remove_policy - remove a policy from the kernel
aa_kernel_interface_write_policy - write a policy to a file descriptor
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
B<typedef struct aa_kernel_interface aa_kernel_interface;>
B<int aa_kernel_interface_new(aa_kernel_interface **kernel_interface, aa_features *kernel_features, const char *apparmorfs);>
B<aa_kernel_interface *aa_kernel_interface_ref(aa_kernel_interface *kernel_interface);>
B<void aa_kernel_interface_unref(aa_kernel_interface *kernel_interface);>
B<int aa_kernel_interface_load_policy(aa_kernel_interface *kernel_interface, const char *buffer, size_t size);>
B<int aa_kernel_interface_load_policy_from_file(aa_kernel_interface *kernel_interface, int dirfd, const char *path);>
B<int aa_kernel_interface_load_policy_from_fd(aa_kernel_interface *kernel_interface, int fd);>
B<int aa_kernel_interface_replace_policy(aa_kernel_interface *kernel_interface, const char *buffer, size_t size);>
B<int aa_kernel_interface_replace_policy_from_file(aa_kernel_interface *kernel_interface, int dirfd, const char *path);>
B<int aa_kernel_interface_replace_policy_from_fd(aa_kernel_interface *kernel_interface, int fd);>
B<int aa_kernel_interface_remove_policy(aa_kernel_interface *kernel_interface, const char *fqname);>
B<int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
The I<aa_kernel_interface> object contains information about the AppArmor
kernel interface for policy loading, replacing, and removing.
The aa_kernel_interface_new() function creates an I<aa_kernel_interface> object
based on an optional I<aa_features> object and an optional path to the apparmor
directory of securityfs, which is typically found at
"/sys/kernel/security/apparmor/". If I<kernel_features> is NULL, then the
features of the current kernel are used. When specifying a valid
I<kernel_features> object, it must be compatible with the features of the
currently running kernel. If I<apparmorfs> is NULL, then the default location
is used. The allocated I<kernel_interface> object must be freed using
aa_kernel_interface_unref().
aa_kernel_interface_ref() increments the reference count on the
I<kernel_interface> object.
aa_kernel_interface_unref() decrements the reference count on the
I<kernel_interface> object and releases all corresponding resources when the
reference count reaches zero.
The aa_kernel_interface_load() family of functions load a policy into the
kernel. The operation will fail if a policy of the same name is already loaded.
Use the aa_kernel_interface_replace() family of functions if you wish to
replace a previously loaded policy with a new policy of the same name. The
aa_kernel_interface_replace() functions can also be used to load a policy that
does not correspond to a previously loaded policy.
When loading or replacing from a buffer, the I<buffer> will contain binary
data. The I<size> argument must specify the size of the I<buffer> argument.
When loading or replacing from a file, the I<dirfd> and I<path> combination are
used to specify the location of the file. See the openat(2) man page for
examples of I<dirfd> and I<path>.
It is also possible to load or replace from a file descriptor specified by the
I<fd> argument. The file must be open for reading and the file offset must be
set appropriately.
The aa_kernel_interface_remove_policy() function can be used to unload a
previously loaded policy. The fully qualified policy name must be specified
with the I<fqname> argument. The operation will fail if a policy matching
I<fqname> is not found.
The aa_kernel_interface_write_policy() function allows for a policy, which is
stored in I<buffer> and consists of I<size> bytes, to be written to a file
descriptor. The I<fd> must be open for writing and the file offset must be set
appropriately.
=head1 RETURN VALUE
The aa_kernel_interface_new() function returns 0 on success and
I<*kernel_interface> will point to an I<aa_kernel_interface> object that must
be freed by aa_kernel_interface_unref(). -1 is returned on error, with errno
set appropriately, and I<*kernel_interface> will be set to NULL.
aa_kernel_features_ref() returns the value of I<kernel_features>.
The aa_kernel_interface_load() family of functions, the
aa_kernel_interface_replace() family of functions,
aa_kernel_interface_remove(), and aa_kernel_interface_write_policy()
return 0 on success. -1 is returned on error, with errno set appropriately.
=head1 ERRORS
The errno value will be set according to the underlying error in the
I<aa_kernel_interface> family of functions that return -1 on error.
=head1 NOTES
All aa_kernel_interface functions described above are present in libapparmor
version 2.10 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
aa_features(3), openat(2) and L<http://wiki.apparmor.net>.
=cut

View file

@ -0,0 +1,125 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd.
# essentially adhere to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa_policy_cache - an opaque object representing an AppArmor policy cache
aa_policy_cache_new - create a new aa_policy_cache object from a path
aa_policy_cache_ref - increments the ref count of an aa_policy_cache object
aa_policy_cache_unref - decrements the ref count and frees the aa_policy_cache object when 0
aa_policy_cache_remove - removes all policy cache files under a path
aa_policy_cache_replace_all - performs a kernel policy replacement of all cached policies
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
B<typedef struct aa_policy_cache aa_policy_cache;>
B<int aa_policy_cache_new(aa_policy_cache **policy_cache, aa_features *kernel_features, int dirfd, const char *path, uint16_t max_caches);>
B<aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache);>
B<void aa_policy_cache_unref(aa_policy_cache *policy_cache);>
B<int aa_policy_cache_remove(int dirfd, const char *path);>
B<int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, aa_kernel_interface *kernel_interface);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
The I<aa_policy_cache> object contains information about a set of AppArmor
policy cache files. The policy cache files are the binary representation of a
human-readable AppArmor profile. The binary representation is the form that is
loaded into the kernel.
The aa_policy_cache_new() function creates an I<aa_policy_cache> object based
upon a directory file descriptor and path. The I<path> must point to a
directory. See the openat(2) man page for examples of I<dirfd> and I<path>. If
I<kernel_features> is NULL, then the features of the current kernel are used.
When specifying a valid I<kernel_features> object, it must be the compatible
with the features of the kernel of interest. The value of I<max_caches> should
be equal to the number of caches that should be allowed before old caches are
automatically reaped. The definition of what is considered to be an old cache
is private to libapparmor. Specifying 0 means that no new caches should be
created and only existing, valid caches may be used. Specifying UINT16_MAX
means that a new cache may be created and that the reaping of old caches is
disabled. The allocated I<aa_policy_cache> object must be freed using
aa_policy_cache_unref().
aa_policy_cache_ref() increments the reference count on the I<policy_cache>
object.
aa_policy_cache_unref() decrements the reference count on the I<policy_cache>
object and releases all corresponding resources when the reference count
reaches zero.
The aa_policy_cache_remove() function deletes all of the policy cache files
based upon a directory file descriptor and path. The I<path> must point to a
directory. See the openat(2) man page for examples of I<dirfd> and I<path>.
The aa_policy_cache_replace_all() function can be used to perform a policy
replacement of all of the cache policies in the cache directory represented by
the I<policy_cache> object. If I<kernel_interface> is NULL, then the current
kernel interface is used. When specifying a valid I<kernel_interface> object,
it must be the interface of the currently running kernel.
=head1 RETURN VALUE
The aa_policy_cache_new() function returns 0 on success and I<*policy_cache>
will point to an I<aa_policy_cache> object that must be freed by
aa_policy_cache_unref(). -1 is returned on error, with errno set appropriately,
and I<*policy_cache> will be set to NULL.
aa_policy_cache_ref() returns the value of I<policy_cache>.
aa_policy_cache_remove() and aa_policy_cache_replace_all() return 0 on success.
-1 is returned on error, with errno set appropriately.
=head1 ERRORS
The errno value will be set according to the underlying error in the
I<aa_policy_cache> family of functions that return -1 on error.
=head1 NOTES
All aa_policy_cache functions described above are present in libapparmor
version 2.10 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
aa_features(3), aa_kernel_interface(3), openat(2) and
L<http://wiki.apparmor.net>.
=cut

View file

@ -0,0 +1,137 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd.
# essentially adhere to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa_query_label - query access permission associated with a label
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
B<int aa_query_label((uint32_t mask, char *query, size_t size,
int *allowed, int *audited);>
B<int aa_query_file_path((uint32_t mask, const char *label, size_t label_len,
const char *path, int *allowed, int *audited);>
B<int aa_query_file_path_len((uint32_t mask, const char *label,
size_t label_len, const char *path, size_t path_len,
int *allowed, int *audited);>
B<int aa_query_link_path_len(const char *label, size_t label_len,
const char *target, size_t target_len,
const char *link, size_t link_len,
int *allowed, int *audited);>
B<int aa_query_link_path(const char *label, const char *target,
const char *link, int *allowed, int *audited);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
The aa_query_label function fetches the current permissions granted by the
specified I<label> in the I<query> string.
The query is a raw binary formatted query, containing the label and
permission query to make. The returned I<allowed> and I<audited> values are
interpreted boolean values, simple stating whether the query is allowed and
if it is audited.
The mask of the query string is a bit mask of permissions to query and is
class type dependent (see AA_CLASS_xxx) entries in I<sys/apparmor.h>.
The format of the query string is also dependent on the B<AA_CLASS> and as
such the the aa_query_xxx helper functions should usually be used instead
of directly using I<aa_query_label>. If directly using the interface the
I<query> string is required to have a header of B<AA_QUERY_CMD_LABEL_SIZE>
that will be used by I<aa_query_label>.
The B<aa_query_file_path> and B<aa_query_file_path_len> functions are helper
function that assemble a properly formatted file path query for the
B<aa_query_label> function. The I<label> is a valid apparmor label as
returned by I<aa_splitcon> with I<label_len> being the length of the I<label>.
The I<path> is any valid filesystem path to query permissions for. For the
B<aa_query_file_path_len> variant the I<path_len> parameter specifies the
number of bytes in the I<path> to use as part of the query.
The B<aa_query_link_path> and B<aa_query_link_path_len> functions are helper
functions that assemble a properly formatted link path query for the
B<aa_query_label> function. The I<link_len> and I<target_len> parameters
specify the number of bytes in the I<link> and I<target> to use as part of
the query.
=head1 RETURN VALUE
On success 0 is returned, and the I<allowed> and I<audited> parameters
contain a boolean value of 0 not allowed/audited or 1 allowed/audited. On
error, -1 is returned, and errno(3) is set appropriately.
=head1 ERRORS
=over 4
=item B<EINVAL>
The requested I<mask> is empty.
The I<size> of the query is E<lt> the query B<AA_QUER?Y_CMD_LABEL_SIZE>
The apparmor kernel module is not loaded or the he kernel interface access
interface is not available
=item B<ENOMEM>
Insufficient memory was available.
=item B<EACCES>
Access to the specified I<label> or query interface was denied.
=item B<ENOENT>
The specified I<label> does not exist or is not visible.
=item B<ERANGE>
The confinement data is too large to fit in the supplied buffer.
=back
=head1 NOTES
The label permissions returned are only valid for the time of the
query and can change at any point in the future.
=head1 BUGS
None known. If you find any, please report them at
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<http://wiki.apparmor.net>.
=cut

View file

@ -0,0 +1,72 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd.
# essentially adhere to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa_splitcon - split the confinement context into a label and mode
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
B<char *aa_splitcon(char *con, char **mode);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
The aa_splitcon() function splits a confinement context into separate label
and mode strings. The @con string is modified so that the label portion is NUL
terminated. The enforcement mode is also NUL terminated and the parenthesis
surrounding the mode are removed. If @mode is non-NULL, it will point to the
first character in the enforcement mode string on success.
The Linux kernel's /proc/E<lt>PIDE<gt>/attr/current interface appends a
trailing newline character to AppArmor contexts that are read from that file.
If @con contains a single trailing newline character, it will be stripped by
aa_splitcon() prior to all other processing.
=head1 RETURN VALUE
Returns a pointer to the first character in the label string. NULL is returned
on error.
=head1 EXAMPLE
Context Label Mode
----------------------------- ------------------ -------
unconfined unconfined NULL
unconfined\n unconfined NULL
/bin/ping (enforce) /bin/ping enforce
/bin/ping (enforce)\n /bin/ping enforce
/usr/sbin/rsyslogd (complain) /usr/sbin/rsyslogd complain
=head1 BUGS
None known. If you find any, please report them at
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
aa_getcon(2) and L<http://wiki.apparmor.net>.
=cut

View file

@ -27,10 +27,31 @@ __BEGIN_DECLS
/*
* Class of public mediation types in the AppArmor policy db
*/
#define AA_CLASS_FILE 2
#define AA_CLASS_DBUS 32
/* Permission flags for the AA_CLASS_FILE mediation class */
#define AA_MAY_EXEC (1 << 0)
#define AA_MAY_WRITE (1 << 1)
#define AA_MAY_READ (1 << 2)
#define AA_MAY_APPEND (1 << 3)
#define AA_MAY_CREATE (1 << 4)
#define AA_MAY_DELETE (1 << 5)
#define AA_MAY_OPEN (1 << 6)
#define AA_MAY_RENAME (1 << 7)
#define AA_MAY_SETATTR (1 << 8)
#define AA_MAY_GETATTR (1 << 9)
#define AA_MAY_SETCRED (1 << 10)
#define AA_MAY_GETCRED (1 << 11)
#define AA_MAY_CHMOD (1 << 12)
#define AA_MAY_CHOWN (1 << 13)
#define AA_MAY_LOCK 0x8000
#define AA_EXEC_MMAP 0x10000
#define AA_MAY_LINK 0x40000
#define AA_MAY_ONEXEC 0x20000000
#define AA_MAY_CHANGE_PROFILE 0x40000000
/* Permission flags for the AA_CLASS_DBUS mediation class */
#define AA_DBUS_SEND (1 << 1)
#define AA_DBUS_RECEIVE (1 << 2)
@ -58,6 +79,7 @@ extern int aa_change_onexec(const char *profile);
extern int aa_change_hatv(const char *subprofiles[], unsigned long token);
extern int (aa_change_hat_vargs)(unsigned long token, int count, ...);
extern char *aa_splitcon(char *con, char **mode);
/* Protypes for introspecting task confinement
* Please see the aa_getcon(2) manpage for information
*/
@ -79,6 +101,17 @@ extern int aa_getpeercon(int fd, char **label, char **mode);
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
int *audit);
extern int aa_query_file_path_len(uint32_t mask, const char *label,
size_t label_len, const char *path,
size_t path_len, int *allowed, int *audited);
extern int aa_query_file_path(uint32_t mask, const char *label,
const char *path, int *allowed, int *audited);
extern int aa_query_link_path_len(const char *label, size_t label_len,
const char *target, size_t target_len,
const char *link, size_t link_len,
int *allowed, int *audited);
extern int aa_query_link_path(const char *label, const char *target,
const char *link, int *allowed, int *audited);
#define __macroarg_counter(Y...) __macroarg_count1 ( , ##Y)
#define __macroarg_count1(Y...) __macroarg_count2 (Y, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
@ -105,52 +138,56 @@ extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
(aa_change_hat_vargs)(T, __macroarg_counter(X), X)
typedef struct aa_features aa_features;
int aa_features_new(aa_features **features, const char *path);
int aa_features_new_from_string(aa_features **features,
const char *string, size_t size);
int aa_features_new_from_kernel(aa_features **features);
aa_features *aa_features_ref(aa_features *features);
void aa_features_unref(aa_features *features);
extern int aa_features_new(aa_features **features, int dirfd, const char *path);
extern int aa_features_new_from_string(aa_features **features,
const char *string, size_t size);
extern int aa_features_new_from_kernel(aa_features **features);
extern aa_features *aa_features_ref(aa_features *features);
extern void aa_features_unref(aa_features *features);
int aa_features_write_to_file(aa_features *features, const char *path);
bool aa_features_is_equal(aa_features *features1, aa_features *features2);
bool aa_features_supports(aa_features *features, const char *str);
extern int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path);
extern bool aa_features_is_equal(aa_features *features1,
aa_features *features2);
extern bool aa_features_supports(aa_features *features, const char *str);
typedef struct aa_kernel_interface aa_kernel_interface;
int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
extern int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
aa_features *kernel_features,
const char *apparmorfs);
aa_kernel_interface *aa_kernel_interface_ref(aa_kernel_interface *kernel_interface);
void aa_kernel_interface_unref(aa_kernel_interface *kernel_interface);
extern aa_kernel_interface *aa_kernel_interface_ref(aa_kernel_interface *kernel_interface);
extern void aa_kernel_interface_unref(aa_kernel_interface *kernel_interface);
int aa_kernel_interface_load_policy(aa_kernel_interface *kernel_interface,
const char *buffer, size_t size);
int aa_kernel_interface_load_policy_from_file(aa_kernel_interface *kernel_interface,
const char *path);
int aa_kernel_interface_load_policy_from_fd(aa_kernel_interface *kernel_interface,
int fd);
int aa_kernel_interface_replace_policy(aa_kernel_interface *kernel_interface,
const char *buffer, size_t size);
int aa_kernel_interface_replace_policy_from_file(aa_kernel_interface *kernel_interface,
const char *path);
int aa_kernel_interface_replace_policy_from_fd(aa_kernel_interface *kernel_interface,
int fd);
int aa_kernel_interface_remove_policy(aa_kernel_interface *kernel_interface,
const char *fqname);
int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size);
extern int aa_kernel_interface_load_policy(aa_kernel_interface *kernel_interface,
const char *buffer, size_t size);
extern int aa_kernel_interface_load_policy_from_file(aa_kernel_interface *kernel_interface,
int dirfd,
const char *path);
extern int aa_kernel_interface_load_policy_from_fd(aa_kernel_interface *kernel_interface,
int fd);
extern int aa_kernel_interface_replace_policy(aa_kernel_interface *kernel_interface,
const char *buffer, size_t size);
extern int aa_kernel_interface_replace_policy_from_file(aa_kernel_interface *kernel_interface,
int dirfd,
const char *path);
extern int aa_kernel_interface_replace_policy_from_fd(aa_kernel_interface *kernel_interface,
int fd);
extern int aa_kernel_interface_remove_policy(aa_kernel_interface *kernel_interface,
const char *fqname);
extern int aa_kernel_interface_write_policy(int fd, const char *buffer,
size_t size);
typedef struct aa_policy_cache aa_policy_cache;
int aa_policy_cache_new(aa_policy_cache **policy_cache,
aa_features *kernel_features, const char *path,
bool create);
aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache);
void aa_policy_cache_unref(aa_policy_cache *policy_cache);
extern int aa_policy_cache_new(aa_policy_cache **policy_cache,
aa_features *kernel_features,
int dirfd, const char *path,
uint16_t max_caches);
extern aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache);
extern void aa_policy_cache_unref(aa_policy_cache *policy_cache);
bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache);
int aa_policy_cache_create(aa_policy_cache *policy_cache);
int aa_policy_cache_remove(const char *path);
int aa_policy_cache_replace_all(aa_policy_cache *policy_cache,
aa_kernel_interface *kernel_interface);
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

View file

@ -17,13 +17,12 @@
#ifndef _SYS_APPARMOR_PRIVATE_H
#define _SYS_APPARMOR_PRIVATE_H 1
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
__BEGIN_DECLS
int _aa_is_blacklisted(const char *name, const char *path);
int _aa_is_blacklisted(const char *name);
void _aa_autofree(void *p);
void _aa_autoclose(int *fd);
@ -31,8 +30,8 @@ void _aa_autofclose(FILE **f);
int _aa_asprintf(char **strp, const char *fmt, ...);
int _aa_dirat_for_each(DIR *dir, const char *name, void *data,
int (* cb)(DIR *, const char *, struct stat *, void *));
int _aa_dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *));
__END_DECLS

View file

@ -67,7 +67,11 @@ tst_aalogmisc_LDADD = .libs/libapparmor.a
tst_features_SOURCES = tst_features.c
tst_features_LDADD = .libs/libapparmor.a
check_PROGRAMS = tst_aalogmisc tst_features
tst_kernel_SOURCES = tst_kernel.c
tst_kernel_LDADD = .libs/libapparmor.a
tst_kernel_LDFLAGS = -pthread
check_PROGRAMS = tst_aalogmisc tst_features tst_kernel
TESTS = $(check_PROGRAMS)
EXTRA_DIST = grammar.y scanner.l libapparmor.map libapparmor.pc

View file

@ -80,7 +80,70 @@ static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
return 0;
}
static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
/* load_features_file - opens and reads a file into @buffer and then NUL-terminates @buffer
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
* @path: name of the file
* @buffer: the buffer to read the features file into (will be NUL-terminated on success)
* @size: the size of @buffer
*
* Returns: The number of bytes copied into @buffer on success (not counting
* the NUL-terminator), else -1 and errno is set. Note that @size must be
* larger than the size of the file or -1 will be returned with errno set to
* ENOBUFS indicating that @buffer was not large enough to contain all of the
* file contents.
*/
static int load_features_file(int dirfd, const char *path,
char *buffer, size_t size)
{
autoclose int file = -1;
char *pos = buffer;
ssize_t len;
file = openat(dirfd, path, O_RDONLY);
if (file < 0) {
PDEBUG("Could not open '%s'\n", path);
return -1;
}
PDEBUG("Opened features \"%s\"\n", path);
if (!size) {
errno = ENOBUFS;
return -1;
}
/* Save room for a NUL-terminator at the end of @buffer */
size--;
do {
len = read(file, pos, size);
if (len > 0) {
size -= len;
pos += len;
}
} while (len > 0 && size);
/**
* Possible error conditions:
* - len == -1: read failed and errno is already set so return -1
* - len > 0: read() never returned 0 (EOF) meaning that @buffer was
* too small to contain all of the file contents so set
* errno to ENOBUFS and return -1
*/
if (len) {
if (len > 0)
errno = ENOBUFS;
PDEBUG("Error reading features file '%s': %m\n", path);
return -1;
}
/* NUL-terminate @buffer */
*pos = 0;
return pos - buffer;
}
static int features_dir_cb(int dirfd, const char *name, struct stat *st,
void *data)
{
struct features_struct *fst = (struct features_struct *) data;
@ -93,36 +156,16 @@ static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
return -1;
if (S_ISREG(st->st_mode)) {
autoclose int file = -1;
int len;
int remaining = fst->size - (fst->pos - fst->buffer);
file = openat(dirfd(dir), name, O_RDONLY);
if (file == -1) {
PDEBUG("Could not open '%s'", name);
len = load_features_file(dirfd, name, fst->pos, remaining);
if (len < 0)
return -1;
}
PDEBUG("Opened features \"%s\"\n", name);
if (st->st_size > remaining) {
PDEBUG("Feature buffer full.");
errno = ENOBUFS;
return -1;
}
do {
len = read(file, fst->pos, remaining);
if (len > 0) {
remaining -= len;
fst->pos += len;
*fst->pos = 0;
}
} while (len > 0);
if (len < 0) {
PDEBUG("Error reading feature file '%s'\n", name);
return -1;
}
fst->pos += len;
} else if (S_ISDIR(st->st_mode)) {
if (_aa_dirat_for_each(dir, name, fst, features_dir_cb))
if (_aa_dirat_for_each(dirfd, name, fst, features_dir_cb))
return -1;
}
@ -132,40 +175,19 @@ static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
return 0;
}
static int handle_features_dir(const char *filename, char *buffer, int size,
char *pos)
static int load_features_dir(int dirfd, const char *path,
char *buffer, int size)
{
struct features_struct fst = { buffer, size, pos };
struct features_struct fst = { buffer, size, buffer };
if (_aa_dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
PDEBUG("Failed evaluating %s\n", filename);
if (_aa_dirat_for_each(dirfd, path, &fst, features_dir_cb)) {
PDEBUG("Failed evaluating %s\n", path);
return -1;
}
return 0;
}
static int load_features_file(const char *name, char *buffer, size_t size)
{
autofclose FILE *f = NULL;
size_t end;
f = fopen(name, "r");
if (!f)
return -1;
errno = 0;
end = fread(buffer, 1, size - 1, f);
if (ferror(f)) {
if (!errno)
errno = EIO;
return -1;
}
buffer[end] = 0;
return 0;
}
static bool islbrace(int c)
{
return c == '{';
@ -334,15 +356,16 @@ static bool walk_one(const char **str, const struct component *component,
}
/**
* aa_features_new - create a new features based on a path
* aa_features_new - create a new aa_features object based on a path
* @features: will point to the address of an allocated and initialized
* aa_features object upon success
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: path to a features file or directory
*
* Returns: 0 on success, -1 on error with errno set and *@features pointing to
* NULL
*/
int aa_features_new(aa_features **features, const char *path)
int aa_features_new(aa_features **features, int dirfd, const char *path)
{
struct stat stat_file;
aa_features *f;
@ -350,7 +373,7 @@ int aa_features_new(aa_features **features, const char *path)
*features = NULL;
if (stat(path, &stat_file) == -1)
if (fstatat(dirfd, path, &stat_file, 0) == -1)
return -1;
f = calloc(1, sizeof(*f));
@ -361,9 +384,9 @@ int aa_features_new(aa_features **features, const char *path)
aa_features_ref(f);
retval = S_ISDIR(stat_file.st_mode) ?
handle_features_dir(path, f->string, STRING_SIZE, f->string) :
load_features_file(path, f->string, STRING_SIZE);
if (retval) {
load_features_dir(dirfd, path, f->string, STRING_SIZE) :
load_features_file(dirfd, path, f->string, STRING_SIZE);
if (retval == -1) {
int save = errno;
aa_features_unref(f);
@ -377,7 +400,7 @@ int aa_features_new(aa_features **features, const char *path)
}
/**
* aa_features_new_from_string - create a new features based on a string
* aa_features_new_from_string - create a new aa_features object based on a string
* @features: will point to the address of an allocated and initialized
* aa_features object upon success
* @string: a NUL-terminated string representation of features
@ -412,7 +435,7 @@ int aa_features_new_from_string(aa_features **features,
}
/**
* aa_features_new_from_kernel - create a new features based on the current kernel
* aa_features_new_from_kernel - create a new aa_features object based on the current kernel
* @features: will point to the address of an allocated and initialized
* aa_features object upon success
*
@ -421,11 +444,11 @@ int aa_features_new_from_string(aa_features **features,
*/
int aa_features_new_from_kernel(aa_features **features)
{
return aa_features_new(features, FEATURES_FILE);
return aa_features_new(features, -1, FEATURES_FILE);
}
/**
* aa_features_ref - increments the ref count of a features
* aa_features_ref - increments the ref count of an aa_features object
* @features: the features
*
* Returns: the features
@ -437,7 +460,7 @@ aa_features *aa_features_ref(aa_features *features)
}
/**
* aa_features_unref - decrements the ref count and frees the features when 0
* aa_features_unref - decrements the ref count and frees the aa_features object when 0
* @features: the features (can be NULL)
*/
void aa_features_unref(aa_features *features)
@ -447,21 +470,24 @@ void aa_features_unref(aa_features *features)
}
/**
* aa_features_write_to_file - write a string representation to a file
* aa_features_write_to_file - write a string representation of an aa_features object to a file
* @features: the features
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: the path to write to
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_features_write_to_file(aa_features *features, const char *path)
int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path)
{
autoclose int fd = -1;
size_t size;
ssize_t retval;
char *string;
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
fd = openat(dirfd, path,
O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1)
return -1;
@ -480,7 +506,7 @@ int aa_features_write_to_file(aa_features *features, const char *path)
}
/**
* aa_features_is_equal - equality test for two features
* aa_features_is_equal - equality test for two aa_features objects
* @features1: the first features (can be NULL)
* @features2: the second features (can be NULL)
*
@ -493,7 +519,7 @@ bool aa_features_is_equal(aa_features *features1, aa_features *features2)
}
/**
* aa_features_supports - provides features support status
* aa_features_supports - provides aa_features object support status
* @features: the features
* @str: the string representation of a feature to check
*

View file

@ -169,6 +169,7 @@ aa_record_event_type lookup_aa_event(unsigned int type)
%%
log_message: audit_type
| dmesg_type
| syslog_type
| audit_dispatch
;
@ -199,6 +200,10 @@ other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
}
;
dmesg_type: TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
;
syslog_type:
syslog_date TOK_ID TOK_SYSLOG_KERNEL audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }

View file

@ -32,6 +32,7 @@
#include <pthread.h>
#include <sys/apparmor.h>
#include "private.h"
/* some non-Linux systems do not define a static value */
#ifndef PATH_MAX
@ -43,6 +44,9 @@
#define default_symbol_version(real, name, version) \
__asm__ (".symver " #real "," #name "@@" #version)
#define UNCONFINED "unconfined"
#define UNCONFINED_SIZE strlen(UNCONFINED)
/**
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
* @mnt: returns buffer with the mountpoint string
@ -152,30 +156,89 @@ static char *procattr_path(pid_t pid, const char *attr)
}
/**
* parse_confinement_mode - get the mode from the confinement context
* parse_unconfined - check for the unconfined label
* @con: the confinement context
* @size: size of the confinement context
* @size: size of the confinement context (not including the NUL terminator)
*
* Modifies con to NUL-terminate the label string and the mode string.
*
* Returns: a pointer to the NUL-terminated mode inside the confinement context
* or NULL if the mode was not found
* Returns: True if the con is the unconfined label or false otherwise
*/
static char *parse_confinement_mode(char *con, int size)
static bool parse_unconfined(char *con, int size)
{
if (strcmp(con, "unconfined") != 0 &&
size > 4 && con[size - 2] == ')') {
int pos = size - 3;
return size == UNCONFINED_SIZE &&
strncmp(con, UNCONFINED, UNCONFINED_SIZE) == 0;
}
/**
* splitcon - split the confinement context into a label and mode
* @con: the confinement context
* @size: size of the confinement context (not including the NUL terminator)
* @strip_newline: true if a trailing newline character should be stripped
* @mode: if non-NULL and a mode is present, will point to mode string in @con
* on success
*
* Modifies the @con string to split it into separate label and mode strings.
* If @strip_newline is true and @con contains a single trailing newline, it
* will be stripped on success (it will not be stripped on error). The @mode
* argument is optional. If @mode is NULL, @con will still be split between the
* label and mode (if present) but @mode will not be set.
*
* Returns: a pointer to the label string or NULL on error
*/
static char *splitcon(char *con, int size, bool strip_newline, char **mode)
{
char *label = NULL;
char *mode_str = NULL;
char *newline = NULL;
if (size == 0)
goto out;
if (strip_newline && con[size - 1] == '\n') {
newline = &con[size - 1];
size--;
}
if (parse_unconfined(con, size)) {
label = con;
goto out;
}
if (size > 3 && con[size - 1] == ')') {
int pos = size - 2;
while (pos > 0 && !(con[pos] == ' ' && con[pos + 1] == '('))
pos--;
if (pos > 0) {
con[pos] = 0; /* overwrite ' ' */
con[size - 2] = 0; /* overwrite trailing ) */
return &con[pos + 2]; /* skip '(' */
con[size - 1] = 0; /* overwrite trailing ) */
mode_str = &con[pos + 2]; /* skip '(' */
label = con;
}
}
return NULL;
out:
if (label && strip_newline && newline)
*newline = 0; /* overwrite '\n', if requested, on success */
if (mode)
*mode = mode_str;
return label;
}
/**
* aa_splitcon - split the confinement context into a label and mode
* @con: the confinement context
* @mode: if non-NULL and a mode is present, will point to mode string in @con
* on success
*
* Modifies the @con string to split it into separate label and mode strings. A
* single trailing newline character will be stripped from @con, if found. The
* @mode argument is optional. If @mode is NULL, @con will still be split
* between the label and mode (if present) but @mode will not be set.
*
* Returns: a pointer to the label string or NULL on error
*/
char *aa_splitcon(char *con, char **mode)
{
return splitcon(con, strlen(con), true, mode);
}
/**
@ -194,7 +257,6 @@ int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
int rc = -1;
int fd, ret;
char *tmp = NULL;
char *mode_str;
int size = 0;
if (!buf || len <= 0) {
@ -237,19 +299,20 @@ int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
goto out;
} else if (size > 0 && buf[size - 1] != 0) {
/* check for null termination */
if (buf[size - 1] == '\n') {
buf[size - 1] = 0;
} else if (len == 0) {
errno = ERANGE;
goto out2;
} else {
buf[size] = 0;
size++;
if (buf[size - 1] != '\n') {
if (len == 0) {
errno = ERANGE;
goto out2;
} else {
buf[size] = 0;
size++;
}
}
mode_str = parse_confinement_mode(buf, size);
if (mode)
*mode = mode_str;
if (splitcon(buf, size, true, mode) != buf) {
errno = EINVAL;
goto out2;
}
}
rc = size;
@ -588,7 +651,6 @@ int aa_getcon(char **label, char **mode)
int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
{
socklen_t optlen = *len;
char *mode_str;
int rc;
if (optlen <= 0 || buf == NULL) {
@ -614,9 +676,11 @@ int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
}
}
mode_str = parse_confinement_mode(buf, optlen);
if (mode)
*mode = mode_str;
if (splitcon(buf, optlen - 1, false, mode) != buf) {
rc = -1;
errno = EINVAL;
goto out;
}
rc = optlen;
out:
@ -786,3 +850,133 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
/**
* aa_query_file_path_len - query access permissions for a file @path
* @mask: permission bits to query
* @label: apparmor label
* @label_len: length of @label (does not include any terminating nul byte)
* @path: file path to query permissions for
* @path_len: length of @path (does not include any terminating nul byte)
* @allowed: upon successful return, will be 1 if query is allowed and 0 if not
* @audited: upon successful return, will be 1 if query should be audited and 0
* if not
*
* Returns: 0 on success else -1 and sets errno. If -1 is returned and errno is
* ENOENT, the subject label in the query string is unknown to the
* kernel.
*/
int aa_query_file_path_len(uint32_t mask, const char *label, size_t label_len,
const char *path, size_t path_len, int *allowed,
int *audited)
{
autofree char *query = NULL;
/* + 1 for null separator */
size_t size = AA_QUERY_CMD_LABEL_SIZE + label_len + 1 + path_len;
query = malloc(size + 1);
if (!query)
return -1;
memcpy(query + AA_QUERY_CMD_LABEL_SIZE, label, label_len);
/* null separator */
query[AA_QUERY_CMD_LABEL_SIZE + label_len] = 0;
query[AA_QUERY_CMD_LABEL_SIZE + label_len + 1] = AA_CLASS_FILE;
memcpy(query + AA_QUERY_CMD_LABEL_SIZE + label_len + 2, path, path_len);
return aa_query_label(mask, query, size , allowed, audited);
}
/**
* aa_query_file_path - query access permissions for a file @path
* @mask: permission bits to query
* @label: apparmor label
* @path: file path to query permissions for
* @allowed: upon successful return, will be 1 if query is allowed and 0 if not
* @audited: upon successful return, will be 1 if query should be audited and 0
* if not
*
* Returns: 0 on success else -1 and sets errno. If -1 is returned and errno is
* ENOENT, the subject label in the query string is unknown to the
* kernel.
*/
int aa_query_file_path(uint32_t mask, const char *label, const char *path,
int *allowed, int *audited)
{
return aa_query_file_path_len(mask, label, strlen(label), path,
strlen(path), allowed, audited);
}
/**
* aa_query_link_path_len - query access permissions for a hard link @link
* @label: apparmor label
* @label_len: length of @label (does not include any terminating nul byte)
* @target: file path that hard link will point to
* @target_len: length of @target (does not include any terminating nul byte)
* @link: file path of hard link
* @link_len: length of @link (does not include any terminating nul byte)
* @allowed: upon successful return, will be 1 if query is allowed and 0 if not
* @audited: upon successful return, will be 1 if query should be audited and 0
* if not
*
* Returns: 0 on success else -1 and sets errno. If -1 is returned and errno is
* ENOENT, the subject label in the query string is unknown to the
* kernel.
*/
int aa_query_link_path_len(const char *label, size_t label_len,
const char *target, size_t target_len,
const char *link, size_t link_len,
int *allowed, int *audited)
{
autofree char *query = NULL;
int rc;
/* + 1 for null separators */
size_t size = AA_QUERY_CMD_LABEL_SIZE + label_len + 1 + target_len +
1 + link_len;
size_t pos = AA_QUERY_CMD_LABEL_SIZE;
query = malloc(size);
if (!query)
return -1;
memcpy(query + pos, label, label_len);
/* null separator */
pos += label_len;
query[pos] = 0;
query[++pos] = AA_CLASS_FILE;
memcpy(query + pos + 1, link, link_len);
/* The kernel does the query in two parts we could similate this
* doing the following, however as long as policy is compiled
* correctly this isn't requied, and it requires and extra round
* trip to the kernel and adds a race on policy replacement between
* the two queries.
*
rc = aa_query_label(AA_MAY_LINK, query, size, allowed, audited);
if (rc || !*allowed)
return rc;
*/
pos += 1 + link_len;
query[pos] = 0;
memcpy(query + pos + 1, target, target_len);
return aa_query_label(AA_MAY_LINK, query, size, allowed, audited);
}
/**
* aa_query_link_path - query access permissions for a hard link @link
* @label: apparmor label
* @target: file path that hard link will point to
* @link: file path of hard link
* @allowed: upon successful return, will be 1 if query is allowed and 0 if not
* @audited: upon successful return, will be 1 if query should be audited and 0
* if not
*
* Returns: 0 on success else -1 and sets errno. If -1 is returned and errno is
* ENOENT, the subject label in the query string is unknown to the
* kernel.
*/
int aa_query_link_path(const char *label, const char *target, const char *link,
int *allowed, int *audited)
{
return aa_query_link_path_len(label, strlen(label), target,
strlen(target), link, strlen(link),
allowed, audited);
}

View file

@ -183,11 +183,12 @@ static int write_policy_fd_to_iface(aa_kernel_interface *kernel_interface,
}
static int write_policy_file_to_iface(aa_kernel_interface *kernel_interface,
const char *iface_file, const char *path)
const char *iface_file,
int dirfd, const char *path)
{
autoclose int fd;
fd = open(path, O_RDONLY);
fd = openat(dirfd, path, O_RDONLY);
if (fd == -1)
return -1;
@ -195,10 +196,12 @@ static int write_policy_file_to_iface(aa_kernel_interface *kernel_interface,
}
/**
* aa_kernel_interface_new - create a new kernel_interface from an optional path
* aa_kernel_interface_new - create a new aa_kernel_interface object from an optional path
* @kernel_interface: will point to the address of an allocated and initialized
* aa_kernel_interface object upon success
* @kernel_features: features representing the currently running kernel
* @kernel_features: features representing the currently running kernel (can be
* NULL and the features of the currently running kernel will
* be used)
* @apparmorfs: path to the apparmor directory of the mounted securityfs (can
* be NULL and the path will be auto discovered)
*
@ -223,9 +226,17 @@ int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
aa_kernel_interface_ref(ki);
ki->dirfd = -1;
ki->supports_setload = kernel_features ?
aa_features_supports(kernel_features, set_load) :
false;
if (kernel_features) {
aa_features_ref(kernel_features);
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
int save = errno;
aa_kernel_interface_unref(ki);
errno = save;
return -1;
}
ki->supports_setload = aa_features_supports(kernel_features, set_load);
aa_features_unref(kernel_features);
if (!apparmorfs) {
if (find_iface_dir(&alloced_apparmorfs) == -1) {
@ -255,7 +266,7 @@ int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
}
/**
* aa_kernel_interface_ref - increments the ref count of a kernel_interface
* aa_kernel_interface_ref - increments the ref count of an aa_kernel_interface object
* @kernel_interface: the kernel_interface
*
* Returns: the kernel_interface
@ -267,7 +278,7 @@ aa_kernel_interface *aa_kernel_interface_ref(aa_kernel_interface *kernel_interfa
}
/**
* aa_kernel_interface_unref - decrements the ref count and frees the kernel_interface when 0
* aa_kernel_interface_unref - decrements the ref count and frees the aa_kernel_interface object when 0
* @kernel_interface: the kernel_interface (can be NULL)
*/
void aa_kernel_interface_unref(aa_kernel_interface *kernel_interface)
@ -280,7 +291,7 @@ void aa_kernel_interface_unref(aa_kernel_interface *kernel_interface)
}
/**
* aa_kernel_interface_load_policy - load a policy into the kernel
* aa_kernel_interface_load_policy - load a policy from a buffer into the kernel
* @kernel_interface: valid aa_kernel_interface
* @buffer: a buffer containing a policy
* @size: the size of the buffer
@ -295,21 +306,21 @@ int aa_kernel_interface_load_policy(aa_kernel_interface *kernel_interface,
}
/**
* aa_kernel_interface_load_policy_from_file - load a policy into the kernel
* aa_kernel_interface_load_policy_from_file - load a policy from a file into the kernel
* @kernel_interface: valid aa_kernel_interface
* @path: path to a policy binary
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_load_policy_from_file(aa_kernel_interface *kernel_interface,
const char *path)
int dirfd, const char *path)
{
return write_policy_file_to_iface(kernel_interface, AA_IFACE_FILE_LOAD,
path);
dirfd, path);
}
/**
* aa_kernel_interface_load_policy_from_fd - load a policy into the kernel
* aa_kernel_interface_load_policy_from_fd - load a policy from a file descriptor into the kernel
* @kernel_interface: valid aa_kernel_interface
* @fd: a pre-opened, readable file descriptor at the correct offset
*
@ -323,7 +334,7 @@ int aa_kernel_interface_load_policy_from_fd(aa_kernel_interface *kernel_interfac
}
/**
* aa_kernel_interface_replace_policy - replace a policy in the kernel
* aa_kernel_interface_replace_policy - replace a policy in the kernel with a policy from a buffer
* @kernel_interface: valid aa_kernel_interface
* @buffer: a buffer containing a policy
* @size: the size of the buffer
@ -339,21 +350,21 @@ int aa_kernel_interface_replace_policy(aa_kernel_interface *kernel_interface,
}
/**
* aa_kernel_interface_replace_policy_from_file - replace a policy in the kernel
* aa_kernel_interface_replace_policy_from_file - replace a policy in the kernel with a policy from a file
* @kernel_interface: valid aa_kernel_interface
* @path: path to a policy binary
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_kernel_interface_replace_policy_from_file(aa_kernel_interface *kernel_interface,
const char *path)
int dirfd, const char *path)
{
return write_policy_file_to_iface(kernel_interface,
AA_IFACE_FILE_REPLACE, path);
AA_IFACE_FILE_REPLACE, dirfd, path);
}
/**
* aa_kernel_interface_replace_policy_from_fd - replace a policy in the kernel
* aa_kernel_interface_replace_policy_from_fd - replace a policy in the kernel with a policy from a file descriptor
* @kernel_interface: valid aa_kernel_interface
* @fd: a pre-opened, readable file descriptor at the correct offset
*

View file

@ -54,6 +54,10 @@ APPARMOR_2.9 {
APPARMOR_2.10 {
global:
aa_query_file_path;
aa_query_file_path_len;
aa_query_link_path;
aa_query_link_path_len;
aa_features_new;
aa_features_new_from_string;
aa_features_new_from_kernel;
@ -76,10 +80,9 @@ APPARMOR_2.10 {
aa_policy_cache_new;
aa_policy_cache_ref;
aa_policy_cache_unref;
aa_policy_cache_is_valid;
aa_policy_cache_create;
aa_policy_cache_remove;
aa_policy_cache_replace_all;
aa_splitcon;
local:
*;
} APPARMOR_2.9;

View file

@ -16,8 +16,8 @@
* Ltd.
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -28,20 +28,21 @@
#include "private.h"
#define CACHE_FEATURES_FILE ".features"
struct aa_policy_cache {
unsigned int ref_count;
aa_features *features;
aa_features *kernel_features;
char *path;
char *features_path;
int dirfd;
};
static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
void *data unused)
{
/* remove regular files */
if (S_ISREG(st->st_mode))
return unlinkat(dirfd(dir), path, 0);
return unlinkat(dirfd, path, 0);
/* do nothing with other file types */
return 0;
@ -49,52 +50,44 @@ static int clear_cache_cb(DIR *dir, const char *path, struct stat *st,
static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
{
struct stat stat_file;
autofclose FILE * f = NULL;
if (aa_policy_cache_remove(policy_cache->dirfd, "."))
return -1;
if (aa_policy_cache_remove(policy_cache->path))
goto error;
create_file:
if (aa_features_write_to_file(features,
policy_cache->features_path) == -1)
goto error;
if (aa_features_write_to_file(features, policy_cache->dirfd,
CACHE_FEATURES_FILE) == -1)
return -1;
aa_features_unref(policy_cache->features);
policy_cache->features = aa_features_ref(features);
return 0;
error:
/* does the dir exist? */
if (stat(policy_cache->path, &stat_file) == -1) {
if (mkdir(policy_cache->path, 0700) == 0)
goto create_file;
PERROR("Can't create cache directory: %s\n",
policy_cache->path);
} else if (!S_ISDIR(stat_file.st_mode)) {
PERROR("File in cache directory location: %s\n",
policy_cache->path);
} else {
PERROR("Can't update cache directory: %s\n",
policy_cache->path);
}
return -1;
}
static int init_cache_features(aa_policy_cache *policy_cache,
aa_features *kernel_features, bool create)
{
if (aa_features_new(&policy_cache->features,
policy_cache->features_path)) {
bool call_create_cache = false;
if (aa_features_new(&policy_cache->features, policy_cache->dirfd,
CACHE_FEATURES_FILE)) {
policy_cache->features = NULL;
if (!create || errno != ENOENT)
return -1;
return create_cache(policy_cache, kernel_features);
/* The cache directory needs to be created */
call_create_cache = true;
} else if (!aa_features_is_equal(policy_cache->features,
kernel_features)) {
if (!create) {
errno = EEXIST;
return -1;
}
/* The cache directory needs to be refreshed */
call_create_cache = true;
}
return 0;
return call_create_cache ?
create_cache(policy_cache, kernel_features) : 0;
}
struct replace_all_cb_data {
@ -102,45 +95,46 @@ struct replace_all_cb_data {
aa_kernel_interface *kernel_interface;
};
static int replace_all_cb(DIR *dir unused, const char *name, struct stat *st,
static int replace_all_cb(int dirfd unused, const char *name, struct stat *st,
void *cb_data)
{
int retval = 0;
if (!S_ISDIR(st->st_mode) && !_aa_is_blacklisted(name, NULL)) {
if (!S_ISDIR(st->st_mode) && !_aa_is_blacklisted(name)) {
struct replace_all_cb_data *data;
autofree char *path = NULL;
data = (struct replace_all_cb_data *) cb_data;
if (asprintf(&path, "%s/%s",
data->policy_cache->path, name) < 0) {
path = NULL;
errno = ENOMEM;
return -1;
}
retval = aa_kernel_interface_replace_policy_from_file(data->kernel_interface,
path);
data->policy_cache->dirfd,
name);
}
return retval;
}
/**
* aa_policy_cache_new - create a new policy_cache from a path
* aa_policy_cache_new - create a new aa_policy_cache object from a path
* @policy_cache: will point to the address of an allocated and initialized
* aa_policy_cache_new object upon success
* @kernel_features: features representing the currently running kernel
* @kernel_features: features representing a kernel (may be NULL if you want to
* use the features of the currently running kernel)
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: path to the policy cache
* @create: true if the cache should be created if it doesn't already exist
* @max_caches: The maximum number of policy caches, one for each unique set of
* kernel features, before older caches are auto-reaped. 0 means
* that no new caches should be created (existing, valid caches
* will be used) and auto-reaping is disabled. UINT16_MAX means
* that a cache can be created and auto-reaping is disabled.
*
* Returns: 0 on success, -1 on error with errno set and *@policy_cache
* pointing to NULL
*/
int aa_policy_cache_new(aa_policy_cache **policy_cache,
aa_features *kernel_features, const char *path,
bool create)
aa_features *kernel_features,
int dirfd, const char *path, uint16_t max_caches)
{
aa_policy_cache *pc;
bool create = max_caches > 0;
*policy_cache = NULL;
@ -149,26 +143,51 @@ int aa_policy_cache_new(aa_policy_cache **policy_cache,
return -1;
}
if (max_caches > 1) {
errno = ENOTSUP;
return -1;
}
pc = calloc(1, sizeof(*pc));
if (!pc) {
errno = ENOMEM;
return -1;
}
pc->dirfd = -1;
aa_policy_cache_ref(pc);
pc->path = strdup(path);
if (!pc->path) {
open:
pc->dirfd = openat(dirfd, path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (pc->dirfd < 0) {
int save;
/* does the dir exist? */
if (create && errno == ENOENT) {
if (mkdirat(dirfd, path, 0700) == 0)
goto open;
PERROR("Can't create cache directory '%s': %m\n", path);
} else if (create) {
PERROR("Can't update cache directory '%s': %m\n", path);
} else {
PDEBUG("Cache directory '%s' does not exist\n", path);
}
save = errno;
aa_policy_cache_unref(pc);
errno = ENOMEM;
errno = save;
return -1;
}
if (asprintf(&pc->features_path, "%s/.features", pc->path) == -1) {
pc->features_path = NULL;
if (kernel_features) {
aa_features_ref(kernel_features);
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
int save = errno;
aa_policy_cache_unref(pc);
errno = ENOMEM;
errno = save;
return -1;
}
pc->kernel_features = kernel_features;
if (init_cache_features(pc, kernel_features, create)) {
int save = errno;
@ -178,14 +197,13 @@ int aa_policy_cache_new(aa_policy_cache **policy_cache,
return -1;
}
pc->kernel_features = aa_features_ref(kernel_features);
*policy_cache = pc;
return 0;
}
/**
* aa_policy_cache_ref - increments the ref count of a policy_cache
* aa_policy_cache_ref - increments the ref count of an aa_policy_cache object
* @policy_cache: the policy_cache
*
* Returns: the policy_cache
@ -197,60 +215,38 @@ aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache)
}
/**
* aa_policy_cache_unref - decrements the ref count and frees the policy_cache when 0
* aa_policy_cache_unref - decrements the ref count and frees the aa_policy_cache object when 0
* @policy_cache: the policy_cache (can be NULL)
*/
void aa_policy_cache_unref(aa_policy_cache *policy_cache)
{
if (policy_cache && atomic_dec_and_test(&policy_cache->ref_count)) {
aa_features_unref(policy_cache->kernel_features);
aa_features_unref(policy_cache->features);
free(policy_cache->features_path);
free(policy_cache->path);
aa_features_unref(policy_cache->kernel_features);
if (policy_cache->dirfd != -1)
close(policy_cache->dirfd);
free(policy_cache);
}
}
/**
* aa_policy_cache_is_valid - checks if the policy_cache is valid for the currently running kernel
* @policy_cache: the policy_cache
*
* Returns: true if the policy_cache is valid for the currently running kernel,
* false if not
*/
bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache)
{
return aa_features_is_equal(policy_cache->features,
policy_cache->kernel_features);
}
/**
* aa_policy_cache_create - creates a valid policy_cache for the currently running kernel
* @policy_cache: the policy_cache
*
* Returns: 0 on success, -1 on error with errno set and features pointing to
* NULL
*/
int aa_policy_cache_create(aa_policy_cache *policy_cache)
{
return create_cache(policy_cache, policy_cache->kernel_features);
}
/**
* aa_policy_cache_remove - removes all policy cache files under a path
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: the path to a policy cache directory
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_policy_cache_remove(const char *path)
int aa_policy_cache_remove(int dirfd, const char *path)
{
return _aa_dirat_for_each(NULL, path, NULL, clear_cache_cb);
return _aa_dirat_for_each(dirfd, path, NULL, clear_cache_cb);
}
/**
* aa_policy_cache_replace_all - performs a kernel policy replacement of all cached policies
* @policy_cache: the policy_cache
* @kernel_interface: the kernel interface to use when doing the replacement
* (may be NULL if the currently running kernel features
* were used when calling aa_policy_cache_new())
*
* Returns: 0 on success, -1 on error with errno set and features pointing to
* NULL
@ -272,7 +268,7 @@ int aa_policy_cache_replace_all(aa_policy_cache *policy_cache,
cb_data.policy_cache = policy_cache;
cb_data.kernel_interface = kernel_interface;
retval = _aa_dirat_for_each(NULL, policy_cache->path, &cb_data,
retval = _aa_dirat_for_each(policy_cache->dirfd, ".", &cb_data,
replace_all_cb);
aa_kernel_interface_unref(kernel_interface);

View file

@ -107,16 +107,15 @@ bool atomic_dec_and_test(unsigned int *v)
return __sync_sub_and_fetch(v, 1) == 0;
}
int _aa_is_blacklisted(const char *name, const char *path)
int _aa_is_blacklisted(const char *name)
{
int name_len;
size_t name_len = strlen(name);
struct ignored_suffix_t *suffix;
/* skip dot files and files with no name */
if (*name == '.' || !strlen(name))
if (!name_len || *name == '.' || !strcmp(name, "README"))
return 1;
name_len = strlen(name);
/* skip blacklisted suffixes */
for (suffix = ignored_suffixes; suffix->text; suffix++) {
char *found;
@ -170,25 +169,31 @@ int _aa_asprintf(char **strp, const char *fmt, ...)
return rc;
}
static int dot_or_dot_dot_filter(const struct dirent *ent)
{
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
return 0;
return 1;
}
/**
* _aa_dirat_for_each: iterate over a directory calling cb for each entry
* @dir: already opened directory (MAY BE NULL)
* @name: name of the directory (MAY BE NULL)
* @dirfd: already opened directory
* @name: name of the directory (NOT NULL)
* @data: data pointer to pass to the callback fn (MAY BE NULL)
* @cb: the callback to pass entry too (NOT NULL)
*
* Iterate over the entries in a directory calling cb for each entry.
* The directory to iterate is determined by a combination of @dir and
* The directory to iterate is determined by a combination of @dirfd and
* @name.
*
* IF @name is a relative path it is determine relative to at @dir if it
* is specified, else it the lookup is done relative to the current
* working directory.
* See the openat section of the open(2) man page for details on valid @dirfd
* and @name combinations. This function does accept AT_FDCWD as @dirfd if
* @name should be considered relative to the current working directory.
*
* If @name is not specified then @dir is used as the directory to iterate
* over.
*
* It is an error if both @name and @dir are null
* Pass "." for @name if @dirfd is the directory to iterate over.
*
* The cb function is called with the DIR in use and the name of the
* file in that directory. If the file is to be opened it should
@ -196,88 +201,52 @@ int _aa_asprintf(char **strp, const char *fmt, ...)
*
* Returns: 0 on success, else -1 and errno is set to the error code
*/
int _aa_dirat_for_each(DIR *dir, const char *name, void *data,
int (* cb)(DIR *, const char *, struct stat *, void *))
int _aa_dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *))
{
autofree struct dirent *dirent = NULL;
DIR *d = NULL;
int error;
autofree struct dirent **namelist = NULL;
autoclose int cb_dirfd = -1;
int i, num_dirs, rc;
if (!cb || (!dir && !name)) {
if (!cb || !name) {
errno = EINVAL;
return -1;
}
if (dir && (!name || *name != '/')) {
dirent = (struct dirent *)
malloc(offsetof(struct dirent, d_name) +
fpathconf(dirfd(dir), _PC_NAME_MAX) + 1);
} else {
dirent = (struct dirent *)
malloc(offsetof(struct dirent, d_name) +
pathconf(name, _PC_NAME_MAX) + 1);
}
if (!dirent) {
errno = ENOMEM;
PDEBUG("could not alloc dirent: %m\n");
cb_dirfd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (cb_dirfd == -1) {
PDEBUG("could not open directory '%s': %m\n", name);
return -1;
}
if (name) {
if (dir && *name != '/') {
int fd = openat(dirfd(dir), name, O_RDONLY);
if (fd == -1)
goto fail;
d = fdopendir(fd);
} else {
d = opendir(name);
}
PDEBUG("Open dir '%s': %s\n", name, d ? "succeeded" : "failed");
if (!(d))
goto fail;
} else { /* dir && !name */
PDEBUG("Recieved cache directory\n");
d = dir;
num_dirs = scandirat(cb_dirfd, ".", &namelist,
dot_or_dot_dot_filter, NULL);
if (num_dirs == -1) {
PDEBUG("scandirat of directory '%s' failed: %m\n", name);
return -1;
}
for (;;) {
struct dirent *ent;
for (rc = 0, i = 0; i < num_dirs; i++) {
/* Must cycle through all dirs so that each one is autofreed */
autofree struct dirent *dir = namelist[i];
struct stat my_stat;
error = readdir_r(d, dirent, &ent);
if (error) {
errno = error; /* readdir_r directly returns an errno */
PDEBUG("readdir_r failed: %m\n");
goto fail;
} else if (!ent) {
break;
}
if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0)
if (rc)
continue;
if (fstatat(dirfd(d), ent->d_name, &my_stat, 0)) {
PDEBUG("stat failed for '%s': %m\n", name);
goto fail;
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
PDEBUG("stat failed for '%s': %m\n", dir->d_name);
rc = -1;
continue;
}
if (cb(d, ent->d_name, &my_stat, data)) {
PDEBUG("dir_for_each callback failed\n");
goto fail;
if (cb(cb_dirfd, dir->d_name, &my_stat, data)) {
PDEBUG("dir_for_each callback failed for '%s'\n",
dir->d_name);
rc = -1;
continue;
}
}
if (d != dir)
closedir(d);
return 0;
fail:
error = errno;
if (d && d != dir)
closedir(d);
errno = error;
return -1;
return rc;
}

View file

@ -355,6 +355,7 @@ yy_flex_debug = 0;
{syslog_time} { yylval->t_str = strdup(yytext); BEGIN(hostname); return(TOK_TIME); }
{audit} { yy_push_state(audit_id, yyscanner); return(TOK_AUDIT); }
{dmesg_timestamp} { yylval->t_str = strdup(yytext); return(TOK_DMESG_STAMP); }
. { /* ignore any non-matched input */ BEGIN(unknown_message); yyless(0); }

View file

@ -0,0 +1,228 @@
/*
* Copyright (c) 2015
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
#include <stdio.h>
#include <string.h>
#include "kernel.c"
static int nullcmp_and_strcmp(const void *s1, const void *s2)
{
/* Return 0 if both pointers are NULL & non-zero if only one is NULL */
if (!s1 || !s2)
return s1 != s2;
return strcmp(s1, s2);
}
static int do_test_splitcon(char *con, int size, bool strip_nl, char **mode,
const char *expected_label,
const char *expected_mode, const char *error)
{
char *label;
int rc = 0;
label = splitcon(con, size, strip_nl, mode);
if (nullcmp_and_strcmp(label, expected_label)) {
fprintf(stderr, "FAIL: %s: label \"%s\" != \"%s\"\n",
error, label, expected_label);
rc = 1;
}
if (mode && nullcmp_and_strcmp(*mode, expected_mode)) {
fprintf(stderr, "FAIL: %s: mode \"%s\" != \"%s\"\n",
error, *mode, expected_mode);
rc = 1;
}
return rc;
}
static int do_test_aa_splitcon(char *con, char **mode,
const char *expected_label,
const char *expected_mode, const char *error)
{
char *label;
int rc = 0;
label = aa_splitcon(con, mode);
if (nullcmp_and_strcmp(label, expected_label)) {
fprintf(stderr, "FAIL: %s: label \"%s\" != \"%s\"\n",
error, label, expected_label);
rc = 1;
}
if (mode && nullcmp_and_strcmp(*mode, expected_mode)) {
fprintf(stderr, "FAIL: %s: mode \"%s\" != \"%s\"\n",
error, *mode, expected_mode);
rc = 1;
}
return rc;
}
#define TEST_SPLITCON(con, size, strip_nl, expected_label, \
expected_mode, error) \
do { \
char c1[] = con; \
char c2[] = con; \
size_t sz = size < 0 ? strlen(con) : size; \
char *mode; \
\
if (do_test_splitcon(c1, sz, strip_nl, &mode, \
expected_label, expected_mode, \
"splitcon: " error)) { \
rc = 1; \
} else if (do_test_splitcon(c2, sz, strip_nl, NULL, \
expected_label, NULL, \
"splitcon: " error " (NULL mode)")) { \
rc = 1; \
} \
} while (0)
#define TEST_AA_SPLITCON(con, expected_label, expected_mode, error) \
do { \
char c1[] = con; \
char c2[] = con; \
char c3[] = con "\n"; \
char *mode; \
\
if (do_test_aa_splitcon(c1, &mode, expected_label, \
expected_mode, "aa_splitcon: " error)) {\
rc = 1; \
} else if (do_test_aa_splitcon(c2, NULL, expected_label,\
NULL, \
"aa_splitcon: " error " (NULL mode)")) {\
rc = 1; \
} else if (do_test_aa_splitcon(c3, &mode, \
expected_label, expected_mode, \
"aa_splitcon: " error " (newline)")) { \
rc = 1; \
} \
} while (0)
static int test_splitcon(void)
{
int rc = 0;
/**
* NOTE: the TEST_SPLITCON() macro automatically generates
* corresponding tests with a NULL mode pointer.
*/
TEST_SPLITCON("", 0, true, NULL, NULL, "empty string test #1");
TEST_SPLITCON("", 0, false, NULL, NULL, "empty string test #2");
TEST_SPLITCON("unconfined", -1, true, "unconfined", NULL,
"unconfined #1");
TEST_SPLITCON("unconfined", -1, false, "unconfined", NULL,
"unconfined #2");
TEST_SPLITCON("unconfined\n", -1, true, "unconfined", NULL,
"unconfined #3");
TEST_SPLITCON("unconfined\n", -1, false, NULL, NULL,
"unconfined #4");
TEST_SPLITCON("label (mode)", -1, true, "label", "mode",
"basic split #1");
TEST_SPLITCON("label (mode)", -1, false, "label", "mode",
"basic split #2");
TEST_SPLITCON("label (mode)\n", -1, true, "label", "mode",
"basic split #3");
TEST_SPLITCON("label (mode)\n", -1, false, NULL, NULL,
"basic split #4");
TEST_SPLITCON("/a/b/c (enforce)", -1, true, "/a/b/c", "enforce",
"path enforce split #1");
TEST_SPLITCON("/a/b/c (enforce)", -1, false, "/a/b/c", "enforce",
"path enforce split #2");
TEST_SPLITCON("/a/b/c (enforce)\n", -1, true, "/a/b/c", "enforce",
"path enforce split #3");
TEST_SPLITCON("/a/b/c (enforce)\n", -1, false, NULL, NULL,
"path enforce split #4");
return rc;
}
static int test_aa_splitcon(void)
{
int rc = 0;
/**
* NOTE: the TEST_AA_SPLITCON() macro automatically generates
* corresponding tests with a NULL mode pointer and contexts with
* trailing newline characters.
*/
TEST_AA_SPLITCON("label (mode)", "label", "mode", "basic split");
TEST_AA_SPLITCON("/a/b/c (enforce)", "/a/b/c", "enforce",
"path enforce split");
TEST_AA_SPLITCON("/a/b/c (complain)", "/a/b/c", "complain",
"path complain split");
TEST_AA_SPLITCON("profile_name (enforce)", "profile_name", "enforce",
"name enforce split");
TEST_AA_SPLITCON("profile_name (complain)", "profile_name", "complain",
"name complain split");
TEST_AA_SPLITCON("unconfined", "unconfined", NULL, "unconfined");
TEST_AA_SPLITCON("(odd) (enforce)", "(odd)", "enforce",
"parenthesized label #1");
TEST_AA_SPLITCON("(odd) (enforce) (enforce)", "(odd) (enforce)",
"enforce", "parenthesized label #2");
TEST_AA_SPLITCON("/usr/bin/😺 (enforce)", "/usr/bin/😺", "enforce",
"non-ASCII path");
TEST_AA_SPLITCON("👍 (enforce)", "👍", "enforce",
"non-ASCII profile name");
/* Negative tests */
TEST_AA_SPLITCON("", NULL, NULL, "empty string test");
TEST_AA_SPLITCON("profile\t(enforce)", NULL, NULL,
"invalid tab separator");
TEST_AA_SPLITCON("profile(enforce)", NULL, NULL,
"invalid missing separator");
return rc;
}
int main(void)
{
int retval, rc = 0;
retval = test_splitcon();
if (retval)
rc = retval;
retval = test_aa_splitcon();
if (retval)
rc = retval;
return rc;
}

View file

@ -3,12 +3,30 @@
%{
#include <aalogparse.h>
#include <sys/apparmor.h>
#include <sys/apparmor_private.h>
%}
%include "typemaps.i"
%include <aalogparse.h>
/**
* swig doesn't like the macro magic we do in apparmor.h and apparmor_private.h
* so the function prototypes must be manually inserted.
*
* Functions that return a negative int and set errno upon error use a special
* %exception directive and must be listed after the %exception below. All
* other functions go here.
*/
/* apparmor.h */
extern char *aa_splitcon(char *con, char **mode);
/* apparmor_private.h */
extern int _aa_is_blacklisted(const char *name);
#ifdef SWIGPYTHON
%exception {
$action
@ -19,9 +37,9 @@
}
#endif
/* swig doesn't like the macro magic we do in apparmor.h so the fn prototypes
* are manually inserted here
*/
/* Functions that return a negative int and set errno upon error go here. */
/* apparmor.h */
extern int aa_is_enabled(void);
extern int aa_find_mountpoint(char **mnt);
@ -39,5 +57,16 @@ extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
extern int aa_getpeercon(int fd, char **label, char **mode);
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
int *audit);
extern int aa_query_file_path_len(uint32_t mask, const char *label,
size_t label_len, const char *path,
size_t path_len, int *allowed, int *audited);
extern int aa_query_file_path(uint32_t mask, const char *label,
const char *path, int *allowed, int *audited);
extern int aa_query_link_path_len(const char *label, size_t label_len,
const char *target, size_t target_len,
const char *link, size_t link_len,
int *allowed, int *audited);
extern int aa_query_link_path(const char *label, const char *target,
const char *link, int *allowed, int *audited);
%exception;

View file

@ -0,0 +1 @@
Sep 9 12:51:36 ubuntu-desktop kernel: [ 97.492562] audit: type=1400 audit(1431116353.523:77): apparmor="DENIED" operation="change_profile" profile="/tests/regression/apparmor/changeprofile" pid=3459 comm="changeprofile" target="/tests/regression/apparmor/rename"

View file

@ -0,0 +1,11 @@
START
File: testcase_changeprofile_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1431116353.523:77
Operation: change_profile
Profile: /tests/regression/apparmor/changeprofile
Command: changeprofile
Name2: /tests/regression/apparmor/rename
PID: 3459
Epoch: 1431116353
Audit subid: 77

View file

@ -0,0 +1 @@
[ 1612.746129] audit: type=1400 audit(1284061910.975:672): apparmor="DENIED" operation="capable" parent=2663 profile="/home/ubuntu/bzr/apparmor/tests/regression/apparmor/syscall_setpriority" pid=7292 comm="syscall_setprio" capability=23 capname="sys_nice"

View file

@ -0,0 +1,12 @@
START
File: testcase_dmesg_capability.in
Event type: AA_RECORD_DENIED
Audit ID: 1284061910.975:672
Operation: capable
Profile: /home/ubuntu/bzr/apparmor/tests/regression/apparmor/syscall_setpriority
Name: sys_nice
Command: syscall_setprio
Parent: 2663
PID: 7292
Epoch: 1284061910
Audit subid: 672

View file

@ -0,0 +1 @@
[ 1597.774866] audit: type=1400 audit(1284061896.005:28): apparmor="DENIED" operation="change_hat" info="unconfined" error=-1 pid=2698 comm="syscall_ptrace"

View file

@ -0,0 +1,11 @@
START
File: testcase_dmesg_changehat_negative_error.in
Event type: AA_RECORD_DENIED
Audit ID: 1284061896.005:28
Operation: change_hat
Command: syscall_ptrace
Info: unconfined
ErrorCode: 1
PID: 2698
Epoch: 1284061896
Audit subid: 28

View file

@ -0,0 +1 @@
[ 97.492562] audit: type=1400 audit(1431116353.523:77): apparmor="DENIED" operation="change_profile" profile="/tests/regression/apparmor/changeprofile" pid=3459 comm="changeprofile" target="/tests/regression/apparmor/rename"

View file

@ -0,0 +1,11 @@
START
File: testcase_dmesg_changeprofile_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1431116353.523:77
Operation: change_profile
Profile: /tests/regression/apparmor/changeprofile
Command: changeprofile
Name2: /tests/regression/apparmor/rename
PID: 3459
Epoch: 1431116353
Audit subid: 77

View file

@ -0,0 +1 @@
[ 2010.738449] audit: type=1400 audit(1284062308.965:276251): apparmor="DENIED" operation="link" parent=19088 profile="/home/ubuntu/bzr/apparmor/tests/regression/apparmor/link" name="/tmp/sdtest.19088-12382-HWH57d/linkfile" pid=19142 comm="link" requested_mask="l" denied_mask="l" fsuid=0 ouid=0 target="/tmp/sdtest.19088-12382-HWH57d/target"

View file

@ -0,0 +1,17 @@
START
File: testcase_dmesg_link_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1284062308.965:276251
Operation: link
Mask: l
Denied Mask: l
fsuid: 0
ouid: 0
Profile: /home/ubuntu/bzr/apparmor/tests/regression/apparmor/link
Name: /tmp/sdtest.19088-12382-HWH57d/linkfile
Command: link
Name2: /tmp/sdtest.19088-12382-HWH57d/target
Parent: 19088
PID: 19142
Epoch: 1284062308
Audit subid: 276251

View file

@ -0,0 +1 @@
[45334.755142] audit: type=1503 audit(1282671283.411:2199): operation="mkdir" pid=4786 parent=4708 profile="/usr/sbin/sshd//ubuntu" requested_mask="c::" denied_mask="c::" fsuid=1000 ouid=1000 name="/tmp/ssh-gRozJw4786/"

View file

@ -0,0 +1,15 @@
START
File: testcase_dmesg_mkdir.in
Event type: AA_RECORD_DENIED
Audit ID: 1282671283.411:2199
Operation: mkdir
Mask: c::
Denied Mask: c::
fsuid: 1000
ouid: 1000
Profile: /usr/sbin/sshd//ubuntu
Name: /tmp/ssh-gRozJw4786/
Parent: 4708
PID: 4786
Epoch: 1282671283
Audit subid: 2199

View file

@ -0,0 +1 @@
[ 878.663418] audit: type=1502 audit(1282626827.320:413): operation="rename_dest" pid=1881 parent=650 profile="/usr/sbin/sshd" requested_mask="wc::" denied_mask="wc::" fsuid=0 ouid=0 name="/var/run/motd"

View file

@ -0,0 +1,15 @@
START
File: testcase_dmesg_rename_dest.in
Event type: AA_RECORD_ALLOWED
Audit ID: 1282626827.320:413
Operation: rename_dest
Mask: wc::
Denied Mask: wc::
fsuid: 0
ouid: 0
Profile: /usr/sbin/sshd
Name: /var/run/motd
Parent: 650
PID: 1881
Epoch: 1282626827
Audit subid: 413

View file

@ -0,0 +1 @@
[ 878.663410] audit: type=1502 audit(1282626827.320:412): operation="rename_src" pid=1881 parent=650 profile="/usr/sbin/sshd" requested_mask="r::" denied_mask="r::" fsuid=0 ouid=0 name="/var/run/motd.new"

View file

@ -0,0 +1,15 @@
START
File: testcase_dmesg_rename_src.in
Event type: AA_RECORD_ALLOWED
Audit ID: 1282626827.320:412
Operation: rename_src
Mask: r::
Denied Mask: r::
fsuid: 0
ouid: 0
Profile: /usr/sbin/sshd
Name: /var/run/motd.new
Parent: 650
PID: 1881
Epoch: 1282626827
Audit subid: 412

View file

@ -0,0 +1 @@
[ 2143.902340] audit: type=1400 audit(1283989336.064:272335): apparmor="STATUS" info="failed to unpack profile" error=-71 pid=4958 comm="apparmor_parser" name="/home/jj/master/tests/regression/apparmor/net_raw" offset=159

View file

@ -0,0 +1,11 @@
START
File: testcase_dmesg_status_offset.in
Event type: AA_RECORD_STATUS
Audit ID: 1283989336.064:272335
Name: /home/jj/master/tests/regression/apparmor/net_raw
Command: apparmor_parser
Info: failed to unpack profile
ErrorCode: 71
PID: 4958
Epoch: 1283989336
Audit subid: 272335

View file

@ -0,0 +1 @@
[ 878.662172] audit: type=1503 audit(1282626827.320:411): operation="truncate" pid=1957 parent=1 profile="/etc/update-motd.d/91-release-upgrade" requested_mask="w::" denied_mask="w::" fsuid=0 ouid=0 name="/var/lib/update-notifier/release-upgrade-available"

View file

@ -0,0 +1,15 @@
START
File: testcase_dmesg_truncate.in
Event type: AA_RECORD_DENIED
Audit ID: 1282626827.320:411
Operation: truncate
Mask: w::
Denied Mask: w::
fsuid: 0
ouid: 0
Profile: /etc/update-motd.d/91-release-upgrade
Name: /var/lib/update-notifier/release-upgrade-available
Parent: 1
PID: 1957
Epoch: 1282626827
Audit subid: 411

View file

@ -50,7 +50,7 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
endif
endif #CFLAGS
EXTRA_CXXFLAGS = ${CFLAGS} ${CXX_WARNINGS} -std=gnu++0x -D_GNU_SOURCE
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x -D_GNU_SOURCE
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
#LEXLIB := -lfl
@ -213,7 +213,7 @@ parser_include.o: parser_include.c parser.h parser_include.h
parser_merge.o: parser_merge.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_symtab.o: parser_symtab.c parser.h

View file

@ -44,19 +44,51 @@ to the policy; this behaviour is modelled after cpp(1).
=over 4
B<PROFILE FILE> = ( [ I<PREAMBLE> ] [ I<PROFILE> ] )*
B<PREAMBLE> = ( I<COMMENT> | I<VARIABLE ASSIGNMENT> | I<INCLUDE> )* (variable assignment must come before the profile)
B<INCLUDE> = '#include' ( I<ABS PATH> | I<MAGIC PATH> )
B<ABS PATH> = '"' path '"' (the path is passed to open(2))
B<MAGIC PATH> = 'E<lt>' relative path 'E<gt>' (the path is relative to F</etc/apparmor.d/>)
B<COMMENT> = '#' I<TEXT>
B<COMMENT> = '#' I<TEXT> [ '\r' ] '\n'
B<TEXT> = any characters
B<PROFILE> = [ I<COMMENT> ... ] [ I<VARIABLE ASSIGNMENT> ... ] ( '"' I<PROGRAM> '"' | I<PROGRAM> ) [ 'flags=(complain)' ]'{' [ ( I<RESOURCE RULE> | I<COMMENT> | I<INCLUDE> | I<SUBPROFILE> | I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<DBUS RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE>) ... ] '}'
B<PROFILE> = ( I<PROFILE HEAD> ) [ I<ATTACHMENT SPECIFICATION> ] [ I<PROFILE FLAG CONDS> ] '{' ( I<RULES> )* '}'
B<SUBPROFILE> = [ I<COMMENT> ... ] ( I<PROGRAMHAT> | 'profile ' I<PROGRAMCHILD> ) '{' [ ( I<FILE RULE> | I<COMMENT> | I<INCLUDE> ) ... ] '}'
B<PROFILE HEAD> = [ 'profile' ] I<FILEGLOB> | 'profile' I<PROFILE NAME>
B<PROFILE NAME> ( I<UNQUOTED PROFILE NAME> | I<QUOTED PROFILE NAME> )
B<QUOTED PROFILE NAME> = '"' I<UNQUOTED PROFILE NAME> '"'
B<UNQUOTED PROFILE NAME> = (must start with alphanumeric character (after variable expansion), or '/' B<AARE> have special meanings; see below. May include I<VARIABLE>. Rules with embedded spaces or tabs must be quoted.)
B<ATTACHMENT SPECIFICATION> = I<FILEGLOB>
B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of I<PROFILE FLAGS> ')'
B<PROFILE FLAGS> = 'complain' | 'audit' | 'enforce' | 'mediate_deleted' | 'attach_disconnected' | 'chroot_relative'
B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<ALIAS RULE> | I<DBUS RULE> )
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
B<SUBPROFILE> = 'profile' I<PROFILE NAME> [ I<ATTACHMENT SPECIFICATION> ] [ I<PROFILE FLAG CONDS> ] '{' ( I<RULES> )* '}'
B<HAT> = ('hat' | '^') I<HATNAME> [ I<PROFILE FLAG CONDS> ] '{' ( I<RULES> )* '}'
B<HATNAME> = ( must start with alphanumeric character. see aa_change_hat(2) for a description of how this "hat" is used. IF '^' is used to start a hat then there is no space between the '^' and I<HATNAME>)
B<QUALIFIER BLOCK> = I<QUALIFIERS> I<BLOCK>
B<ACCESS TYPE> = ( 'allow' | 'deny' )
@ -69,7 +101,7 @@ B<CAPABILITY LIST> = ( I<CAPABILITY> )+
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
capabilities(7))
B<NETWORK RULE> = [ I<QUALIFIERS> 'network' [ [ I<DOMAIN> [ I<TYPE> | I<PROTOCOL> ] ] | [ I<PROTOCOL> ] ] ','
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
B<DOMAIN> = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' | 'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' ) ','
@ -77,15 +109,9 @@ B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
B<PROTOCOL> = ( 'tcp' | 'udp' | 'icmp' )
B<PROGRAM> = (non-whitespace characters except for '^', must start with '/'. Embedded spaces or tabs must be quoted.)
B<PROGRAMHAT> = '^' (non-whitespace characters; see aa_change_hat(2) for a description of how this "hat" is used.)
B<PROGRAMCHILD> = I<SUBPROFILE> name
B<MOUNT RULE> = ( I<MOUNT> | I<REMOUNT> | I<UMOUNT> )
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ -E<gt> [ I<MOUNTPOINT FILEGLOB> ]
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ '-E<gt>' [ I<MOUNTPOINT FILEGLOB> ]
B<REMOUNT> = [ I<QUALIFIERS> ] 'remount' [ I<MOUNT CONDITIONS> ] I<MOUNTPOINT FILEGLOB>
@ -105,7 +131,7 @@ B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec'
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ -E<gt> I<PROGRAMCHILD> ]
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
B<SOURCE FILEGLOB> = I<FILEGLOB>
@ -201,11 +227,11 @@ B<UNIX ATTR COND> 'attr' '=' ( I<AARE> | '(' '"' I<AARE> '"' | I<AARE> ')' )
B<UNIX OPT COND> 'opt' '=' ( I<AARE> | '(' '"' I<AARE> '"' | I<AARE> ')' )
B<RLIMIT RULE> = 'set' 'rlimit' [I<RLIMIT> 'E<lt>=' I<RLIMIT VALUE> ] ','
B<RLIMIT RULE> = 'set' 'rlimit' [I<RLIMIT> 'E<lt>=' I<RLIMIT VALUE> ]
B<RLIMIT> = ( 'cpu' | 'fsize' | 'data' | 'stack' | 'core' | 'rss' | 'nofile' | 'ofile' | 'as' | 'nproc' | 'memlock' | 'locks' | 'sigpending' | 'msgqueue' | 'nice' | 'rtprio' | 'rttime' )
B<RLIMIT VALUE> = ( I<RLIMIT SIZE> | I<RLIMIT NUMBER> | I <RLIMIT NICE> )
B<RLIMIT VALUE> = ( I<RLIMIT SIZE> | I<RLIMIT NUMBER> | I<RLIMIT NICE> )
B<RLIMIT SIZE> = I<NUMBER> ( 'K' | 'M' | 'G' ) Only applies to RLIMIT of 'fsize', 'data', 'stack', 'core', 'rss', 'as', 'memlock', 'msgqueue'.
@ -213,7 +239,7 @@ B<RLIMIT NUMBER> = number from 0 to max rlimit value. Only applies ot RLIMIT of
B<RLIMIT NICE> = a number between -20 and 19. Only applies to RLIMIT of 'nice'
B<FILE RULE> = [ I<QUALIFIERS> ] [ 'owner' ] ( 'file' | [ 'file' ] ( I<FILEGLOB> I<ACCESS> | I<ACCESS> I<FILEGLOB> ) [ -E<gt> <EXEC TARGET> ] ) ','
B<FILE RULE> = [ I<QUALIFIERS> ] [ 'owner' ] ( 'file' | [ 'file' ] ( I<FILEGLOB> I<ACCESS> | I<ACCESS> I<FILEGLOB> ) [ '-E<gt>' I<EXEC TARGET> ] )
B<FILEGLOB> = ( I<QUOTED FILEGLOB> | I<UNQUOTED FILEGLOB> )
@ -227,19 +253,19 @@ B<EXEC TRANSITION> = ( 'ix' | 'ux' | 'Ux' | 'px' | 'Px' | 'cx' | 'Cx' | 'pix' |
B<EXEC TARGET> = name (requires I<EXEC TRANSITION> specified)
B<LINK RULE> = I<QUALIFIERS> [ 'owner' ] 'link' [ 'subset' ] <FILEGLOB> ( 'to' | '-E<gt>' ) <FILEGLOB> ','
B<LINK RULE> = I<QUALIFIERS> [ 'owner' ] 'link' [ 'subset' ] I<FILEGLOB> ( 'to' | '-E<gt>' ) I<FILEGLOB>
B<VARIABLE> = '@{' I<ALPHA> [ ( I<ALPHANUMERIC> | '_' ) ... ] '}'
B<VARIABLE ASSIGNMENT> = I<VARIABLE> ('=' | '+=') (space separated values)
B<ALIAS RULE> = I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ','
B<ALIAS RULE> = I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH>
B<ALPHA> = ('a', 'b', 'c', ... 'z', 'A', 'B', ... 'Z')
B<ALPHANUMERIC> = ('0', '1', '2', ... '9', 'a', 'b', 'c', ... 'z', 'A', 'B', ... 'Z')
B<CHANGE_PROFILE RULE> = 'change_profile' [ I<EXEC COND> ] [ -E<gt> I<PROGRAMCHILD> ]
B<CHANGE_PROFILE RULE> = 'change_profile' [ I<EXEC COND> ] [ '-E<gt>' I<PROFILE NAME> ]
B<EXEC COND> = I<FILEGLOB>
@ -334,7 +360,7 @@ modes:
- transition to subprofile on execute with fallback to unconfined
=item B<Cux>
=item B<CUx>
- transition to subprofile on execute with fallback to unconfined -- scrub the environment
@ -506,7 +532,7 @@ determine the profile to transition to from the executable name. It
is however possible to specify the name of the profile that the transition
should use.
The name of the profile to transition to is specified using the '->'
The name of the profile to transition to is specified using the '-E<gt>'
followed by the name of the profile to transition to. Eg.
/bin/** px -> profile,
@ -546,8 +572,9 @@ or trailing the file glob. Eg.
/** rw, # trailing permissions
When a leading permissions is used further rule options and context
When leading permissions are used further rule options and context
may be allowed, Eg.
l /foo -> /bar, # lead 'l' link permission is equivalent to link rules
=back
@ -567,25 +594,27 @@ Eg.
/link* rw,
link subset /link* -> /**,
The link rule allows linking of /link to both /file1 or /file2 by
name however because the /link file has 'rw' permissions it is not
allowed to link to /file1 because that would grant an access path
to /file1 with more permissions than the 'r' permissions the profile
specifies.
The link rule allows linking of /link to both /file1 or /file2 by
name however because the /link file has 'rw' permissions it is not
allowed to link to /file1 because that would grant an access path
to /file1 with more permissions than the 'r' permissions the profile
specifies.
A link of /link to /file2 would be allowed because the 'rw' permissions
of /link are a subset of the 'rwk' permissions for /file1.
A link of /link to /file2 would be allowed because the 'rw' permissions
of /link are a subset of the 'rwk' permissions for /file1.
The link rule is equivalent to specifying the 'l' link permission as
a leading permission with no other file access permissions. When this
is done the link rule options can be specified.
The following link rule is equivalent to the 'l' permission file rule
link /foo -> bar,
l /foo -> /bar,
File rules that specify the 'l' permission and don't specify the extend
link permissions map to link rules as follows.
/foo l,
l /foo,
link subset /foo -> /**,
@ -1301,6 +1330,12 @@ Rule qualifiers can modify the rule and/or permissions within the rule.
=over 4
=item B<allow>
Specifies that permissions requests that match the rule are allowed. This
is the default value for rules and does not need to be specified. Conflicts
with the I<deny> qualifier.
=item B<audit>
Specifies that permissions requests that match the rule should be recorded
@ -1309,7 +1344,8 @@ to the audit log.
=item B<deny>
Specifies that permissions requests that match the rule should be denied
without logging. Can be combined with 'audit' to enable logging.
without logging. Can be combined with 'audit' to enable logging. Conflicts
with the I<allow> qualifier.
=item B<owner>
@ -1318,6 +1354,16 @@ referenced by the permission check.
=back
=head3 Qualifier Blocks
Rule Qualifiers can be applied to multiple rules at a time by grouping the
rules into a rule block.
audit {
/foo r,
network,
}
=head2 #include mechanism
AppArmor provides an easy abstraction mechanism to group common file

View file

@ -183,6 +183,12 @@ defined as an absolute paths.
Set the location of the apparmor security filesystem (default is
"/sys/kernel/security/apparmor").
=item -M n, --features-file n
Use the features file located at path "n" (default is
/etc/apparmor.d/cache/.features). If the --cache-loc option is present, the
".features" file in the specified cache directory is used.
=item -m n, --match-string n
Only use match features "n".

View file

@ -29,9 +29,9 @@
#define AA_MAY_WRITE (1 << 1)
#define AA_MAY_READ (1 << 2)
#define AA_MAY_APPEND (1 << 3)
#define AA_MAY_LINK (1 << 4)
#define AA_MAY_LOCK (1 << 5)
#define AA_EXEC_MMAP (1 << 6)
#define AA_OLD_MAY_LINK (1 << 4)
#define AA_OLD_MAY_LOCK (1 << 5)
#define AA_OLD_EXEC_MMAP (1 << 6)
#define AA_EXEC_PUX (1 << 7)
#define AA_EXEC_UNSAFE (1 << 8)
#define AA_EXEC_INHERIT (1 << 9)
@ -42,8 +42,8 @@
#define AA_BASE_PERMS (AA_MAY_EXEC | AA_MAY_WRITE | \
AA_MAY_READ | AA_MAY_APPEND | \
AA_MAY_LINK | AA_MAY_LOCK | \
AA_EXEC_PUX | AA_EXEC_MMAP | \
AA_OLD_MAY_LINK | AA_OLD_MAY_LOCK | \
AA_EXEC_PUX | AA_OLD_EXEC_MMAP | \
AA_EXEC_UNSAFE | AA_EXEC_INHERIT | \
AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
AA_EXEC_MOD_2 | AA_EXEC_MOD_3)
@ -95,8 +95,8 @@
#define ALL_USER_EXEC (AA_USER_EXEC | AA_USER_EXEC_TYPE)
#define ALL_OTHER_EXEC (AA_OTHER_EXEC | AA_OTHER_EXEC_TYPE)
#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
(AA_MAY_LINK << AA_OTHER_SHIFT))
#define AA_LINK_BITS ((AA_OLD_MAY_LINK << AA_USER_SHIFT) | \
(AA_OLD_MAY_LINK << AA_OTHER_SHIFT))
#define SHIFT_MODE(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
| ((MODE) & ~AA_FILE_PERMS))
@ -104,7 +104,7 @@
| ((MODE) & ~AA_FILE_PERMS))
#define AA_LINK_SUBSET_TEST (AA_MAY_LINK << 1)
#define AA_LINK_SUBSET_TEST (AA_OLD_MAY_LINK << 1)
#define LINK_SUBSET_BITS ((AA_LINK_SUBSET_TEST << AA_USER_SHIFT) | \
(AA_LINK_SUBSET_TEST << AA_OTHER_SHIFT))
#define LINK_TO_LINK_SUBSET(X) (((X) << 1) & AA_LINK_SUBSET_TEST)
@ -137,9 +137,9 @@ enum pattern_t {
#define HAS_MAY_WRITE(mode) ((mode) & AA_MAY_WRITE)
#define HAS_MAY_APPEND(mode) ((mode) & AA_MAY_APPEND)
#define HAS_MAY_EXEC(mode) ((mode) & AA_MAY_EXEC)
#define HAS_MAY_LINK(mode) ((mode) & AA_MAY_LINK)
#define HAS_MAY_LOCK(mode) ((mode) & AA_MAY_LOCK)
#define HAS_EXEC_MMAP(mode) ((mode) & AA_EXEC_MMAP)
#define HAS_MAY_LINK(mode) ((mode) & AA_OLD_MAY_LINK)
#define HAS_MAY_LOCK(mode) ((mode) & AA_OLD_MAY_LOCK)
#define HAS_EXEC_MMAP(mode) ((mode) & AA_OLD_EXEC_MMAP)
#define HAS_EXEC_UNSAFE(mode) ((mode) & AA_EXEC_UNSAFE)
#define HAS_CHANGE_PROFILE(mode) ((mode) & AA_CHANGE_PROFILE)
@ -161,3 +161,6 @@ static inline int is_merged_x_consistent(int a, int b)
}
#endif /* ! _IMMUNIX_H */
/* LocalWords: MMAP
*/

View file

@ -16,7 +16,6 @@
* Ltd.
*/
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
@ -29,10 +28,10 @@
#include "lib.h"
#include "parser.h"
int dirat_for_each(DIR *dir, const char *name, void *data,
int (* cb)(DIR *, const char *, struct stat *, void *))
int dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *))
{
int retval = _aa_dirat_for_each(dir, name, data, cb);
int retval = _aa_dirat_for_each(dirfd, name, data, cb);
if (retval)
PDEBUG("dirat_for_each failed: %m\n");

View file

@ -9,8 +9,8 @@
#define asprintf _aa_asprintf
int dirat_for_each(DIR *dir, const char *name, void *data,
int (* cb)(DIR *, const char *, struct stat *, void *));
int dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *));
int isodigit(char c);
long strntol(const char *str, const char **endptr, int base, long maxval,

View file

@ -35,13 +35,13 @@
#include "../immunix.h"
aare_rules::~aare_rules(void)
{
if (root)
root->release();
aare_reset_matchflags();
unique_perms.clear();
expr_map.clear();
}
bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
@ -50,40 +50,15 @@ bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
return add_rule_vec(deny, perms, audit, 1, &rule, flags);
}
#define FLAGS_WIDTH 2
#define MATCH_FLAGS_SIZE (sizeof(uint32_t) * 8 - 1)
MatchFlag *match_flags[FLAGS_WIDTH][MATCH_FLAGS_SIZE];
DenyMatchFlag *deny_flags[FLAGS_WIDTH][MATCH_FLAGS_SIZE];
#define EXEC_MATCH_FLAGS_SIZE (AA_EXEC_COUNT *2 * 2 * 2) /* double for each of ix pux, unsafe x bits * u::o */
MatchFlag *exec_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE]; /* mods + unsafe + ix + pux * u::o */
ExactMatchFlag *exact_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE]; /* mods + unsafe + ix + pux *u::o */
void aare_reset_matchflags(void)
{
uint32_t i, j;
#define RESET_FLAGS(group, size) { \
for (i = 0; i < FLAGS_WIDTH; i++) { \
for (j = 0; j < size; j++) { \
if ((group)[i][j]) delete (group)[i][j]; \
(group)[i][j] = NULL; \
} \
} \
}
RESET_FLAGS(match_flags, MATCH_FLAGS_SIZE);
RESET_FLAGS(deny_flags, MATCH_FLAGS_SIZE);
RESET_FLAGS(exec_match_flags, EXEC_MATCH_FLAGS_SIZE);
RESET_FLAGS(exact_match_flags, EXEC_MATCH_FLAGS_SIZE);
#undef RESET_FLAGS
}
void aare_rules::add_to_rules(Node *tree, Node *perms)
{
if (reverse)
flip_tree(tree);
if (root)
root = new AltNode(root, new CatNode(tree, perms));
Node *base = expr_map[perms];
if (base)
expr_map[perms] = new AltNode(base, tree);
else
root = new CatNode(tree, perms);
expr_map[perms] = tree;
}
static Node *cat_with_null_seperator(Node *l, Node *r)
@ -91,84 +66,6 @@ static Node *cat_with_null_seperator(Node *l, Node *r)
return new CatNode(new CatNode(l, new CharNode(0)), r);
}
static Node *convert_file_perms(int deny, uint32_t perms, uint32_t audit,
bool exact_match)
{
Node *accept;
assert(perms != 0);
/* 0x7f == 4 bits x mods + 1 bit unsafe mask + 1 bit ix, + 1 pux after shift */
#define EXTRACT_X_INDEX(perm, shift) (((perm) >> (shift + 7)) & 0x7f)
/* the permissions set is assumed to be non-empty if any audit
* bits are specified */
accept = NULL;
for (unsigned int n = 0; perms && n < (sizeof(perms) * 8); n++) {
uint32_t mask = 1 << n;
if (!(perms & mask))
continue;
int ai = audit & mask ? 1 : 0;
perms &= ~mask;
Node *flag;
if (mask & ALL_AA_EXEC_TYPE)
/* these cases are covered by EXEC_BITS */
continue;
if (deny) {
if (deny_flags[ai][n]) {
flag = deny_flags[ai][n];
} else {
//fprintf(stderr, "Adding deny ai %d mask 0x%x audit 0x%x\n", ai, mask, audit & mask);
deny_flags[ai][n] = new DenyMatchFlag(mask, audit & mask);
flag = deny_flags[ai][n];
}
} else if (mask & AA_EXEC_BITS) {
uint32_t eperm = 0;
uint32_t index = 0;
if (mask & AA_USER_EXEC) {
eperm = mask | (perms & AA_USER_EXEC_TYPE);
index = EXTRACT_X_INDEX(eperm, AA_USER_SHIFT);
} else {
eperm = mask | (perms & AA_OTHER_EXEC_TYPE);
index = EXTRACT_X_INDEX(eperm, AA_OTHER_SHIFT) + (AA_EXEC_COUNT << 2);
}
//fprintf(stderr, "index %d eperm 0x%x\n", index, eperm);
if (exact_match) {
if (exact_match_flags[ai][index]) {
flag = exact_match_flags[ai][index];
} else {
exact_match_flags[ai][index] = new ExactMatchFlag(eperm, audit & mask);
flag = exact_match_flags[ai][index];
}
} else {
if (exec_match_flags[ai][index]) {
flag = exec_match_flags[ai][index];
} else {
exec_match_flags[ai][index] = new MatchFlag(eperm, audit & mask);
flag = exec_match_flags[ai][index];
}
}
} else {
if (match_flags[ai][n]) {
flag = match_flags[ai][n];
} else {
match_flags[ai][n] = new MatchFlag(mask, audit & mask);
flag = match_flags[ai][n];
}
}
if (accept)
accept = new AltNode(accept, flag);
else
accept = flag;
} /* for ... */
return accept;
}
bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
int count, const char **rulev, dfaflags_t flags)
{
@ -202,7 +99,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
if (reverse)
flip_tree(tree);
accept = convert_file_perms(deny, perms, audit, exact_match);
accept = unique_perms.insert(deny, perms, audit, exact_match);
if (flags & DFA_DUMP_RULE_EXPR) {
cerr << "rule: ";
@ -235,6 +132,30 @@ void *aare_rules::create_dfa(size_t *size, dfaflags_t flags)
{
char *buffer = NULL;
/* finish constructing the expr tree from the different permission
* set nodes */
PermExprMap::iterator i = expr_map.begin();
if (i != expr_map.end()) {
if (flags & DFA_CONTROL_TREE_SIMPLE) {
Node *tmp = simplify_tree(i->second, flags);
root = new CatNode(tmp, i->first);
} else
root = new CatNode(i->second, i->first);
for (i++; i != expr_map.end(); i++) {
Node *tmp;
if (flags & DFA_CONTROL_TREE_SIMPLE) {
tmp = simplify_tree(i->second, flags);
} else
tmp = i->second;
root = new AltNode(root, new CatNode(tmp, i->first));
}
}
/* dumping of the none simplified tree without -O no-expr-simplify
* is broken because we need to build the tree above first, and
* simplification is woven into the build. Reevaluate how to fix
* this debug dump.
*/
label_nodes(root);
if (flags & DFA_DUMP_TREE) {
cerr << "\nDFA: Expression Tree\n";
@ -243,7 +164,13 @@ void *aare_rules::create_dfa(size_t *size, dfaflags_t flags)
}
if (flags & DFA_CONTROL_TREE_SIMPLE) {
root = simplify_tree(root, flags);
/* This is old total tree, simplification point
* For now just do simplification up front. It gets most
* of the benefit running on the smaller chains, and is
* overall faster because there are less nodes. Reevaluate
* once tree simplification is rewritten
*/
//root = simplify_tree(root, flags);
if (flags & DFA_DUMP_SIMPLE_TREE) {
cerr << "\nDFA: Simplified Expression Tree\n";

View file

@ -26,14 +26,78 @@
#include "apparmor_re.h"
#include "expr-tree.h"
class UniquePerm {
public:
bool deny;
bool exact_match;
uint32_t perms;
uint32_t audit;
bool operator<(UniquePerm const &rhs)const
{
if (deny == rhs.deny) {
if (exact_match == rhs.exact_match) {
if (perms == rhs.perms)
return audit < rhs.audit;
return perms < rhs.perms;
}
return exact_match;
}
return deny;
}
};
class UniquePermsCache {
public:
typedef map<UniquePerm, Node*> UniquePermMap;
typedef UniquePermMap::iterator iterator;
UniquePermMap nodes;
UniquePermsCache(void) { };
~UniquePermsCache() { clear(); }
void clear()
{
for (iterator i = nodes.begin(); i != nodes.end(); i++) {
delete i->second;
}
nodes.clear();
}
Node *insert(bool deny, uint32_t perms, uint32_t audit,
bool exact_match)
{
UniquePerm tmp = { deny, exact_match, perms, audit };
iterator res = nodes.find(tmp);
if (res == nodes.end()) {
Node *node;
if (deny)
node = new DenyMatchFlag(perms, audit);
else if (exact_match)
node = new ExactMatchFlag(perms, audit);
else
node = new MatchFlag(perms, audit);
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
if (val.second == false)
return val.first->second;
return node;
}
return res->second;
}
};
typedef std::map<Node *, Node *> PermExprMap;
class aare_rules {
Node *root;
void add_to_rules(Node *tree, Node *perms);
public:
UniquePermsCache unique_perms;
PermExprMap expr_map;
public:
int reverse;
int rule_count;
aare_rules(): root(NULL), reverse(0), rule_count(0) { };
aare_rules(int reverse): root(NULL), reverse(reverse), rule_count(0) { };
aare_rules(void): root(NULL), unique_perms(), expr_map(), reverse(0), rule_count(0) { };
aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { };
~aare_rules();
bool add_rule(const char *rule, int deny, uint32_t perms,
@ -43,6 +107,4 @@ public:
void *create_dfa(size_t *size, dfaflags_t flags);
};
void aare_reset_matchflags(void);
#endif /* __LIBAA_RE_RULES_H */

View file

@ -100,7 +100,10 @@ struct cond_entry_list {
struct cod_entry {
char *ns;
char *name;
char *link_name;
union {
char *link_name;
char *onexec;
};
char *nt_name;
Profile *prof; /* Special profile defined
* just for this executable */
@ -333,7 +336,6 @@ extern int abort_on_error;
extern int skip_bad_cache_rebuild;
extern int mru_skip_cache;
extern int debug_cache;
extern struct timespec mru_tstamp;
/* provided by parser_lex.l (cannot be used in tst builds) */
extern FILE *yyin;
@ -359,8 +361,6 @@ extern int clear_and_convert_entry(std::string& buffer, char *entry);
extern int process_regex(Profile *prof);
extern int post_process_entry(struct cod_entry *entry);
extern void reset_regex(void);
extern int process_policydb(Profile *prof);
extern int process_policy_ents(Profile *prof);

View file

@ -32,7 +32,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <unordered_map>
#include <string>
@ -120,7 +119,7 @@ struct cb_struct {
const char *filename;
};
static int include_dir_cb(DIR *dir unused, const char *name, struct stat *st,
static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
void *data)
{
struct cb_struct *d = (struct cb_struct *) data;
@ -179,7 +178,7 @@ void include_filename(char *filename, int search)
struct cb_struct data = { fullpath, filename };
fclose(include_file);
include_file = NULL;
if (dirat_for_each(NULL, fullpath, &data, include_dir_cb)) {
if (dirat_for_each(AT_FDCWD, fullpath, &data, include_dir_cb)) {
yyerror(_("Could not process include directory"
" '%s' in '%s'"), fullpath, filename);;
}
@ -443,7 +442,7 @@ LT_EQUAL <=
({IDS}|{QUOTED_ID}) {
yylval.id = processid(yytext, yyleng);
POP_AND_RETURN(TOK_ID);
RETURN_TOKEN(TOK_ID);
}
}
@ -612,7 +611,7 @@ LT_EQUAL <=
PUSH_AND_RETURN(state, token);
}
<INITIAL,NETWORK_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
{END_OF_RULE} {
if (YY_START != INITIAL)
POP_NODUMP();

View file

@ -28,7 +28,6 @@
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
/* enable the following line to get voluminous debug info */
/* #define DEBUG */
@ -77,7 +76,7 @@ int abort_on_error = 0; /* stop processing profiles if error */
int skip_bad_cache_rebuild = 0;
int mru_skip_cache = 1;
int debug_cache = 0;
struct timespec mru_tstamp;
struct timespec cache_tstamp, mru_policy_tstamp;
static char *apparmorfs = NULL;
static char *cacheloc = NULL;
@ -398,7 +397,7 @@ static int process_arg(int c, char *optarg)
}
break;
case 'M':
if (aa_features_new(&features, optarg)) {
if (aa_features_new(&features, AT_FDCWD, optarg)) {
fprintf(stderr,
"Failed to load features from '%s': %m\n",
optarg);
@ -601,7 +600,7 @@ int process_binary(int option, aa_kernel_interface *kernel_interface,
if (kernel_load) {
if (option == OPTION_ADD) {
retval = profilename ?
aa_kernel_interface_load_policy_from_file(kernel_interface, profilename) :
aa_kernel_interface_load_policy_from_file(kernel_interface, AT_FDCWD, profilename) :
aa_kernel_interface_load_policy_from_fd(kernel_interface, 0);
if (retval == -1) {
retval = errno;
@ -611,7 +610,7 @@ int process_binary(int option, aa_kernel_interface *kernel_interface,
}
} else if (option == OPTION_REPLACE) {
retval = profilename ?
aa_kernel_interface_replace_policy_from_file(kernel_interface, profilename) :
aa_kernel_interface_replace_policy_from_file(kernel_interface, AT_FDCWD, profilename) :
aa_kernel_interface_replace_policy_from_fd(kernel_interface, 0);
if (retval == -1) {
retval = errno;
@ -646,12 +645,12 @@ int process_binary(int option, aa_kernel_interface *kernel_interface,
void reset_parser(const char *filename)
{
memset(&mru_tstamp, 0, sizeof(mru_tstamp));
memset(&mru_policy_tstamp, 0, sizeof(mru_policy_tstamp));
memset(&cache_tstamp, 0, sizeof(cache_tstamp));
mru_skip_cache = 1;
free_aliases();
free_symtabs();
free_policies();
reset_regex();
reset_include_stack(filename);
}
@ -811,7 +810,7 @@ struct dir_cb_data {
};
/* data - pointer to a dir_cb_data */
static int profile_dir_cb(DIR *dir unused, const char *name, struct stat *st,
static int profile_dir_cb(int dirfd unused, const char *name, struct stat *st,
void *data)
{
int rc = 0;
@ -828,7 +827,7 @@ static int profile_dir_cb(DIR *dir unused, const char *name, struct stat *st,
}
/* data - pointer to a dir_cb_data */
static int binary_dir_cb(DIR *dir unused, const char *name, struct stat *st,
static int binary_dir_cb(int dirfd unused, const char *name, struct stat *st,
void *data)
{
int rc = 0;
@ -898,13 +897,15 @@ int main(int argc, char *argv[])
if ((!skip_cache && (write_cache || !skip_read_cache)) ||
force_clear_cache) {
uint16_t max_caches = write_cache && cond_clear_cache ? 1 : 0;
if (!cacheloc && asprintf(&cacheloc, "%s/cache", basedir) == -1) {
PERROR(_("Memory allocation error."));
return 1;
}
if (force_clear_cache) {
if (aa_policy_cache_remove(cacheloc)) {
if (aa_policy_cache_remove(AT_FDCWD, cacheloc)) {
PERROR(_("Failed to clear cache files (%s): %s\n"),
cacheloc, strerror(errno));
return 1;
@ -916,31 +917,25 @@ int main(int argc, char *argv[])
if (create_cache_dir)
pwarn(_("The --create-cache-dir option is deprecated. Please use --write-cache.\n"));
retval = aa_policy_cache_new(&policy_cache, features, cacheloc,
write_cache);
retval = aa_policy_cache_new(&policy_cache, features,
AT_FDCWD, cacheloc, max_caches);
if (retval) {
if (errno != ENOENT) {
if (errno != ENOENT && errno != EEXIST) {
PERROR(_("Failed setting up policy cache (%s): %s\n"),
cacheloc, strerror(errno));
return 1;
}
write_cache = 0;
skip_read_cache = 0;
} else if (!aa_policy_cache_is_valid(policy_cache)) {
if (write_cache && cond_clear_cache &&
aa_policy_cache_create(policy_cache)) {
if (show_cache)
if (show_cache) {
if (max_caches > 0)
PERROR("Cache write disabled: Cannot create cache '%s': %m\n",
cacheloc);
write_cache = 0;
skip_read_cache = 1;
} else if (!write_cache || !cond_clear_cache) {
if (show_cache)
else
PERROR("Cache read/write disabled: Policy cache is invalid\n");
write_cache = 0;
skip_read_cache = 1;
}
write_cache = 0;
skip_read_cache = 1;
}
}
@ -965,14 +960,14 @@ int main(int argc, char *argv[])
}
if (profilename && S_ISDIR(stat_file.st_mode)) {
int (*cb)(DIR *dir, const char *name, struct stat *st,
int (*cb)(int dirfd, const char *name, struct stat *st,
void *data);
struct dir_cb_data cb_data;
cb_data.dirname = profilename;
cb_data.cachedir = cacheloc;
cb = binary_input ? binary_dir_cb : profile_dir_cb;
if ((retval = dirat_for_each(NULL, profilename,
if ((retval = dirat_for_each(AT_FDCWD, profilename,
&cb_data, cb))) {
PDEBUG("Failed loading profiles from %s\n",
profilename);

View file

@ -53,7 +53,7 @@
int is_blacklisted(const char *name, const char *path)
{
int retval = _aa_is_blacklisted(name, path);
int retval = _aa_is_blacklisted(name);
if (retval == -1)
PERROR("Ignoring: '%s'\n", path ? path : name);
@ -332,7 +332,7 @@ reeval:
case COD_READ_CHAR:
if (read_implies_exec) {
PDEBUG("Parsing mode: found %s READ imply X\n", mode_desc);
mode |= AA_MAY_READ | AA_EXEC_MMAP;
mode |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
} else {
PDEBUG("Parsing mode: found %s READ\n", mode_desc);
mode |= AA_MAY_READ;
@ -355,12 +355,12 @@ reeval:
case COD_LINK_CHAR:
PDEBUG("Parsing mode: found %s LINK\n", mode_desc);
mode |= AA_MAY_LINK;
mode |= AA_OLD_MAY_LINK;
break;
case COD_LOCK_CHAR:
PDEBUG("Parsing mode: found %s LOCK\n", mode_desc);
mode |= AA_MAY_LOCK;
mode |= AA_OLD_MAY_LOCK;
break;
case COD_INHERIT_CHAR:
@ -439,7 +439,7 @@ reeval:
case COD_MMAP_CHAR:
PDEBUG("Parsing mode: found %s MMAP\n", mode_desc);
mode |= AA_EXEC_MMAP;
mode |= AA_OLD_EXEC_MMAP;
break;
case COD_EXEC_CHAR:

View file

@ -492,6 +492,8 @@ static int process_profile_name_xmatch(Profile *prof)
return TRUE;
}
static int warn_change_profile = 1;
static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
{
std::string tbuf;
@ -514,9 +516,9 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
* dfa states like it does for pcre
*/
if ((entry->mode >> AA_OTHER_SHIFT) & AA_EXEC_INHERIT)
entry->mode |= AA_EXEC_MMAP << AA_OTHER_SHIFT;
entry->mode |= AA_OLD_EXEC_MMAP << AA_OTHER_SHIFT;
if ((entry->mode >> AA_USER_SHIFT) & AA_EXEC_INHERIT)
entry->mode |= AA_EXEC_MMAP << AA_USER_SHIFT;
entry->mode |= AA_OLD_EXEC_MMAP << AA_USER_SHIFT;
/* the link bit on the first pair entry should not get masked
* out by a deny rule, as both pieces of the link pair must
@ -530,8 +532,9 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
if (entry->deny) {
if ((entry->mode & ~(AA_LINK_BITS | AA_CHANGE_PROFILE)) &&
!dfarules->add_rule(tbuf.c_str(), entry->deny,
entry->mode & ~AA_LINK_BITS,
entry->audit & ~AA_LINK_BITS, dfaflags))
entry->mode & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
entry->audit & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
dfaflags))
return FALSE;
} else if (entry->mode & ~AA_CHANGE_PROFILE) {
if (!dfarules->add_rule(tbuf.c_str(), entry->deny, entry->mode,
@ -562,11 +565,25 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
}
if (entry->mode & AA_CHANGE_PROFILE) {
const char *vec[3];
std::string lbuf;
std::string lbuf, xbuf;
int index = 1;
/* allow change_profile for all execs */
vec[0] = "/[^\\x00]*";
if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit && warn_change_profile) {
/* don't have profile name here, so until this code
* gets refactored just throw out a generic warning
*/
fprintf(stderr, "Warning kernel does not support audit modifier for change_profile rule.\n");
warn_change_profile = 0;
}
if (entry->onexec) {
ptype = convert_aaregex_to_pcre(entry->onexec, 0, glob_default, xbuf, &pos);
if (ptype == ePatternInvalid)
return FALSE;
vec[0] = xbuf.c_str();
} else
/* allow change_profile for all execs */
vec[0] = "/[^/\\x00][^\\x00]*";
if (entry->ns) {
int pos;
@ -576,12 +593,12 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
vec[index++] = tbuf.c_str();
/* regular change_profile rule */
if (!dfarules->add_rule_vec(0, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags))
if (!dfarules->add_rule_vec(entry->deny, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags))
return FALSE;
/* onexec rules - both rules are needed for onexec */
if (!dfarules->add_rule_vec(0, AA_ONEXEC, 0, 1, vec, dfaflags))
if (!dfarules->add_rule_vec(entry->deny, AA_ONEXEC, 0, 1, vec, dfaflags))
return FALSE;
if (!dfarules->add_rule_vec(0, AA_ONEXEC, 0, index, vec, dfaflags))
if (!dfarules->add_rule_vec(entry->deny, AA_ONEXEC, 0, index, vec, dfaflags))
return FALSE;
}
return TRUE;
@ -762,8 +779,6 @@ int process_profile_policydb(Profile *prof)
prof->policy.rules = NULL;
}
aare_reset_matchflags();
error = 0;
out:
@ -773,11 +788,6 @@ out:
return error;
}
void reset_regex(void)
{
aare_reset_matchflags();
}
#ifdef UNIT_TEST
#include "unit_test.h"

View file

@ -254,6 +254,11 @@ static int process_variables_in_entries(struct cod_entry *entry_list)
error = expand_entry_variables(&entry->name);
if (error)
return error;
if (entry->link_name) {
error = expand_entry_variables(&entry->link_name);
if (error)
return error;
}
}
return 0;

View file

@ -244,6 +244,7 @@ void add_local_entry(Profile *prof);
%type <flags> flagval
%type <cap> caps
%type <cap> capability
%type <id> change_profile_head
%type <user_entry> change_profile
%type <set_var> TOK_SET_VAR
%type <bool_var> TOK_BOOL_VAR
@ -258,6 +259,7 @@ void add_local_entry(Profile *prof);
%type <boolean> opt_flags
%type <boolean> opt_perm_mode
%type <id> opt_ns
%type <id> ns_id
%type <id> opt_id
%type <prefix> opt_prefix
%type <fmode> dbus_perm
@ -297,8 +299,10 @@ opt_profile_flag: { /* nothing */ $$ = 0; }
| TOK_PROFILE { $$ = 1; }
| hat_start { $$ = 2; }
ns_id: TOK_COLON id_or_var TOK_COLON { $$ = $2; }
opt_ns: { /* nothing */ $$ = NULL; }
| TOK_COLON TOK_ID TOK_COLON { $$ = $2; }
| ns_id { $$ = $1; }
opt_id: { /* nothing */ $$ = NULL; }
| TOK_ID { $$ = $1; }
@ -785,13 +789,23 @@ rules: rules opt_prefix unix_rule
$$ = $1;
}
rules: rules change_profile
rules: rules opt_prefix change_profile
{
PDEBUG("matched: rules change_profile\n");
PDEBUG("rules change_profile: (%s)\n", $2->name);
if (!$2)
PDEBUG("rules change_profile: (%s)\n", $3->name);
if (!$3)
yyerror(_("Assert: `change_profile' returned NULL."));
add_entry_to_policy($1, $2);
if ($2.owner)
yyerror(_("owner prefix not allowed on unix rules"));
if ($2.deny && $2.audit) {
$3->deny = 1;
} else if ($2.deny) {
$3->deny = 1;
$3->audit = $3->mode;
} else if ($2.audit) {
$3->audit = $3->mode;
}
add_entry_to_policy($1, $3);
$$ = $1;
};
@ -1043,11 +1057,11 @@ opt_named_transition:
$$.ns = NULL;
$$.name = $2;
}
| TOK_ARROW TOK_COLON id_or_var TOK_COLON id_or_var
| TOK_ARROW ns_id id_or_var
{
$$.present = 1;
$$.ns = $3;
$$.name = $5;
$$.ns = $2;
$$.name = $3;
};
rule: file_rule { $$ = $1; }
@ -1120,7 +1134,7 @@ file_rule_tail: opt_unsafe id_or_var file_mode id_or_var
yyerror(_("missing an end of line character? (entry: %s)"), $2);
};
link_rule: TOK_LINK opt_subset_flag TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
link_rule: TOK_LINK opt_subset_flag id_or_var TOK_ARROW id_or_var TOK_END_OF_RULE
{
struct cod_entry *entry;
PDEBUG("Matched: link tok_id (%s) -> (%s)\n", $3, $5);
@ -1481,29 +1495,38 @@ file_mode: TOK_MODE
free($1);
}
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_ID TOK_END_OF_RULE
change_profile_head: TOK_CHANGE_PROFILE opt_id
{
if ($2 && !($2[0] == '/' || strncmp($2, "@{", 2) == 0))
yyerror(_("Exec condition must begin with '/'."));
$$ = $2;
}
change_profile: change_profile_head TOK_END_OF_RULE
{
struct cod_entry *entry;
PDEBUG("Matched change_profile: tok_id (%s)\n", $3);
entry = new_entry(NULL, $3, AA_CHANGE_PROFILE, NULL);
char *rule = strdup("**");
if (!rule)
yyerror(_("Memory allocation error."));
PDEBUG("Matched change_profile,\n");
entry = new_entry(NULL, rule, AA_CHANGE_PROFILE, $1);
if (!entry)
yyerror(_("Memory allocation error."));
PDEBUG("change_profile,\n");
$$ = entry;
};
change_profile: change_profile_head TOK_ARROW opt_ns TOK_ID TOK_END_OF_RULE
{
struct cod_entry *entry;
PDEBUG("Matched change_profile: tok_id (:%s://%s)\n", $3 ? $3 : "", $4);
entry = new_entry($3, $4, AA_CHANGE_PROFILE, $1);
if (!entry)
yyerror(_("Memory allocation error."));
PDEBUG("change_profile.entry: (%s)\n", entry->name);
$$ = entry;
};
change_profile: TOK_CHANGE_PROFILE TOK_ARROW TOK_COLON TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
{
struct cod_entry *entry;
PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $4, $6);
entry = new_entry($4, $6, AA_CHANGE_PROFILE, NULL);
if (!entry)
yyerror(_("Memory allocation error."));
PDEBUG("change_profile.entry: (%s)\n", entry->name);
$$ = entry;
};
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
{
if ($2 == 0) {

View file

@ -25,6 +25,8 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <utime.h>
#include "lib.h"
#include "parser.h"
@ -70,22 +72,27 @@ bool valid_cached_file_version(const char *cachename)
}
void set_mru_tstamp(struct timespec t)
void set_cache_tstamp(struct timespec t)
{
mru_skip_cache = 0;
mru_tstamp = t;
cache_tstamp = t;
}
void update_mru_tstamp(FILE *file, const char *name)
{
struct stat stat_file;
if (fstat(fileno(file), &stat_file) || (mru_tstamp.tv_sec == 0 && mru_tstamp.tv_nsec == 0))
if (fstat(fileno(file), &stat_file))
return;
if (mru_t_cmp(stat_file.st_mtim)) {
if (tstamp_cmp(mru_policy_tstamp, stat_file.st_mtim) < 0)
/* keep track of the most recent policy tstamp */
mru_policy_tstamp = stat_file.st_mtim;
if (tstamp_is_null(cache_tstamp))
return;
if (tstamp_cmp(stat_file.st_mtim, cache_tstamp) > 0) {
if (debug_cache)
pwarn("%s: file '%s' is newer than cache file\n", progname, name);
mru_skip_cache = 1;
}
}
}
char *cache_filename(const char *cachedir, const char *basename)
@ -109,7 +116,7 @@ void valid_read_cache(const char *cachename)
if (stat(cachename, &stat_bin) == 0 &&
stat_bin.st_size > 0) {
if (valid_cached_file_version(cachename))
set_mru_tstamp(stat_bin.st_ctim);
set_cache_tstamp(stat_bin.st_mtim);
else if (!cond_clear_cache)
write_cache = 0;
} else {
@ -159,6 +166,12 @@ void install_cache(const char *cachetmpname, const char *cachename)
/* Only install the generate cache file if it parsed correctly
and did not have write/close errors */
if (cachetmpname) {
struct timeval t;
/* set the mtime of the cache file to the most newest mtime
* of policy files used to generate it
*/
TIMESPEC_TO_TIMEVAL(&t, &mru_policy_tstamp);
utimes(cachetmpname, &t);
if (rename(cachetmpname, cachename) < 0) {
pwarn("Warning failed to write cache: %s\n", cachename);
unlink(cachetmpname);

View file

@ -19,12 +19,14 @@
#ifndef __AA_POLICY_CACHE_H
#define __AA_POLICY_CACHE_H
extern struct timespec mru_tstamp;
extern struct timespec cache_tstamp, mru_policy_tstamp;
/* returns true if time is more recent than mru_tstamp */
#define mru_t_cmp(a) \
(((a).tv_sec == (mru_tstamp).tv_sec) ? \
(a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec)
#define tstamp_cmp(a, b) \
(((a).tv_sec == (b).tv_sec) ? \
((a).tv_nsec - (b).tv_nsec) : \
((a).tv_sec - (b).tv_sec))
#define tstamp_is_null(a) ((a).tv_sec == 0 && (a).tv_nsec == 0)
extern int show_cache;
extern int skip_cache;
@ -36,7 +38,7 @@ extern int create_cache_dir; /* create the cache dir if missing? */
extern int mru_skip_cache;
extern int debug_cache;
void set_mru_tstamp(struct timespec t);
void set_cache_tstamp(struct timespec t);
void update_mru_tstamp(FILE *file, const char *path);
bool valid_cached_file_version(const char *cachename);
char *cache_filename(const char *cachedir, const char *basename);

View file

@ -458,6 +458,12 @@ verify_binary_equality "Deny of ungranted perm" \
"/t { /foo/[abc] r, }"
verify_binary_equality "change_profile == change_profile -> **" \
"/t { change_profile, }" \
"/t { change_profile -> **, }" \
"/t { change_profile /**, }" \
"/t { change_profile /** -> **, }"
if [ $fails -ne 0 -o $errors -ne 0 ]
then
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit change_profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit change_profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> /bin/foo,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit change_profile to a hat
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> /bin/foo//bar,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit change_profile with name space
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> :foo:/bin/foo,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION audit change_profile with a variable (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
/usr/bin/foo {
audit change_profile -> @{LIBVIRT}-foo,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION audit change_profile with variable+regex (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
/usr/bin/foo {
audit change_profile -> @{LIBVIRT}-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit change_profile with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> "/bin/foo",
}
/usr/bin/foo2 {
audit change_profile -> "/bin/ foo",
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit change_profile to a hat with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> "/bin/foo//bar",
}
/usr/bin/foo2 {
audit change_profile -> "/bin/foo// bar",
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit change_profile with name space with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> ":foo:/bin/foo",
}
/usr/bin/foo2 {
audit change_profile -> ":foo:/bin/ foo",
}

View file

@ -0,0 +1,24 @@
#
#=DESCRIPTION audit change_profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> /bin/*,
}
/usr/bin/foo2 {
audit change_profile -> /bin/**,
}
/usr/bin/foo3 {
audit change_profile -> /bin/?,
}
/usr/bin/foo4 {
audit change_profile -> /bin/[ab],
}
/usr/bin/foo5 {
audit change_profile -> /bin/[^ab],
}

View file

@ -0,0 +1,69 @@
#
#=DESCRIPTION audit change_profile to a hat
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> /bin/foo//bar,
}
/usr/bin/foo2 {
audit change_profile -> /bin/foo//ba*,
}
/usr/bin/foo3 {
audit change_profile -> /bin/foo//ba**,
}
/usr/bin/foo4 {
audit change_profile -> /bin/foo//ba?,
}
/usr/bin/foo5 {
audit change_profile -> /bin/foo//ba[ab],
}
/usr/bin/foo6 {
audit change_profile -> /bin/foo//ba[^ab],
}
/usr/bin/foo7 {
audit change_profile -> /bin/fo*//bar,
}
/usr/bin/foo8 {
audit change_profile -> /bin/fo**//bar,
}
/usr/bin/foo9 {
audit change_profile -> /bin/fo?//bar,
}
/usr/bin/foo10 {
audit change_profile -> /bin/fo[ab]//bar,
}
/usr/bin/foo11 {
audit change_profile -> /bin/fo[^ab]//bar,
}
/usr/bin/foo12 {
audit change_profile -> /bin/fo*//ba*,
}
/usr/bin/foo13 {
audit change_profile -> /bin/fo**//ba**,
}
/usr/bin/foo14 {
audit change_profile -> /bin/fo?//ba?,
}
/usr/bin/foo15 {
audit change_profile -> /bin/fo[ab]//ba[ab],
}
/usr/bin/foo16 {
audit change_profile -> /bin/fo[^ab]//ba[^ab],
}

View file

@ -0,0 +1,67 @@
#
#=DESCRIPTION audit change_profile with name space
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> :foo:/bin/foo,
}
/usr/bin/foo2 {
audit change_profile -> :foo:/bin/fo*,
}
/usr/bin/foo3 {
audit change_profile -> :foo:/bin/fo**,
}
/usr/bin/foo4 {
audit change_profile -> :foo:/bin/fo?,
}
/usr/bin/foo5 {
audit change_profile -> :foo:/bin/fo[ab],
}
/usr/bin/foo6 {
audit change_profile -> :foo:/bin/fo[^ab],
}
/usr/bin/foo7 {
audit change_profile -> :fo*:/bin/foo,
}
/usr/bin/foo8 {
audit change_profile -> :fo**:/bin/foo,
}
/usr/bin/foo9 {
audit change_profile -> :fo?:/bin/foo,
}
/usr/bin/foo10 {
audit change_profile -> :fo[ab]:/bin/foo,
}
/usr/bin/foo11 {
audit change_profile -> :fo[^ab]:/bin/foo,
}
/usr/bin/foo12 {
audit change_profile -> :fo*:/bin/fo*,
}
/usr/bin/foo13 {
audit change_profile -> :fo**:/bin/fo**,
}
/usr/bin/foo14 {
audit change_profile -> :fo?:/bin/fo?,
}
/usr/bin/foo15 {
audit change_profile -> :fo[ab]:/bin/fo[ab],
}
/usr/bin/foo16 {
audit change_profile -> :fo[^ab]:/bin/fo[^ab],
}

View file

@ -0,0 +1,51 @@
#
#=DESCRIPTION audit change_profile with a variable (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
@{LIBVIRT_RE}="libvirt*"
/usr/bin/foo {
audit change_profile -> @{LIBVIRT}-fo*,
}
/usr/bin/foo2 {
audit change_profile -> @{LIBVIRT}-fo**,
}
/usr/bin/foo3 {
audit change_profile -> @{LIBVIRT}-fo[ab],
}
/usr/bin/foo4 {
audit change_profile -> @{LIBVIRT}-fo[^ab],
}
/usr/bin/foo5 {
audit change_profile -> @{LIBVIRT}-fo?,
}
/usr/bin/foo6 {
audit change_profile -> @{LIBVIRT_RE}-foo,
}
/usr/bin/foo7 {
audit change_profile -> @{LIBVIRT_RE}-fo*,
}
/usr/bin/foo8 {
audit change_profile -> @{LIBVIRT_RE}-fo**,
}
/usr/bin/foo9 {
audit change_profile -> @{LIBVIRT_RE}-fo?,
}
/usr/bin/foo10 {
audit change_profile -> @{LIBVIRT_RE}-fo[ab],
}
/usr/bin/foo11 {
audit change_profile -> @{LIBVIRT_RE}-fo[^ab],
}

View file

@ -0,0 +1,25 @@
#
#=DESCRIPTION audit change_profile with just res
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> *,
}
/usr/bin/foo2 {
audit change_profile -> **,
}
/usr/bin/foo3 {
audit change_profile -> ?,
}
/usr/bin/foo4 {
audit change_profile -> [ab],
}
/usr/bin/foo5 {
audit change_profile -> [^ab],
}

View file

@ -0,0 +1,65 @@
#
#=DESCRIPTION audit change_profile with just res, child profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> *//ab,
}
/usr/bin/foo2 {
audit change_profile -> **//ab,
}
/usr/bin/foo3 {
audit change_profile -> ?//ab,
}
/usr/bin/foo4 {
audit change_profile -> [ab]//ab,
}
/usr/bin/foo5 {
audit change_profile -> [^ab]//ab,
}
/usr/bin/foo6 {
audit change_profile -> ab//*,
}
/usr/bin/foo7 {
audit change_profile -> ab//**,
}
/usr/bin/foo8 {
audit change_profile -> ab//?,
}
/usr/bin/foo9 {
audit change_profile -> ab//[ab],
}
/usr/bin/foo10 {
audit change_profile -> ab//[^ab],
}
/usr/bin/foo11 {
audit change_profile -> *//*,
}
/usr/bin/foo12 {
audit change_profile -> **//*,
}
/usr/bin/foo13 {
audit change_profile -> ?//*,
}
/usr/bin/foo14 {
audit change_profile -> [ab]//*,
}
/usr/bin/foo15 {
audit change_profile -> [^ab]//*,
}

View file

@ -0,0 +1,65 @@
#
#=DESCRIPTION audit change_profile with just re, namespace
#=EXRESULT PASS
#
/usr/bin/foo {
audit change_profile -> :ab:*,
}
/usr/bin/foo2 {
audit change_profile -> :ab:**,
}
/usr/bin/foo3 {
audit change_profile -> :ab:?,
}
/usr/bin/foo4 {
audit change_profile -> :ab:[ab],
}
/usr/bin/foo5 {
audit change_profile -> :ab:[^ab],
}
/usr/bin/foo6 {
audit change_profile -> :*:ab,
}
/usr/bin/foo7 {
audit change_profile -> :**:ab,
}
/usr/bin/foo8 {
audit change_profile -> :?:ab,
}
/usr/bin/foo9 {
audit change_profile -> :[ab]:ab,
}
/usr/bin/foo10 {
audit change_profile -> :[^ab]:ab,
}
/usr/bin/foo11 {
audit change_profile -> :*:*,
}
/usr/bin/foo12 {
audit change_profile -> :**:**,
}
/usr/bin/foo13 {
audit change_profile -> :?:?,
}
/usr/bin/foo14 {
audit change_profile -> :[ab]:[ab],
}
/usr/bin/foo15 {
audit change_profile -> :[^ab]:[^ab],
}

View file

@ -0,0 +1,45 @@
#
#=DESCRIPTION audit change_profile re with quotes
#=EXRESULT PASS
#
/usr/bin/foo5 {
audit change_profile -> "/bin/*",
}
/usr/bin/foo6 {
audit change_profile -> "/bin/**",
}
/usr/bin/foo7 {
audit change_profile -> "/bin/[ab]",
}
/usr/bin/foo8 {
audit change_profile -> "/bin/[^ab]",
}
/usr/bin/foo10 {
audit change_profile -> "/bin/?ab",
}
/usr/bin/foo11 {
audit change_profile -> "/bin/ *",
}
/usr/bin/foo12 {
audit change_profile -> "/bin/ **",
}
/usr/bin/foo13 {
audit change_profile -> "/bin/ [ab]",
}
/usr/bin/foo14 {
audit change_profile -> "/bin/ [^ab]",
}
/usr/bin/foo15 {
audit change_profile -> "/bin/ ?ab",
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit allow change_profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> /bin/foo,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit allow change_profile to a hat
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> /bin/foo//bar,
}

View file

@ -0,0 +1,7 @@
#
#=DESCRIPTION audit allow change_profile with name space
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> :foo:/bin/foo,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION audit allow change_profile with a variable (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
/usr/bin/foo {
audit allow change_profile -> @{LIBVIRT}-foo,
}

View file

@ -0,0 +1,10 @@
#
#=DESCRIPTION audit allow change_profile with variable+regex (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
/usr/bin/foo {
audit allow change_profile -> @{LIBVIRT}-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*,
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit allow change_profile with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> "/bin/foo",
}
/usr/bin/foo2 {
audit allow change_profile -> "/bin/ foo",
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit allow change_profile to a hat with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> "/bin/foo//bar",
}
/usr/bin/foo2 {
audit allow change_profile -> "/bin/foo// bar",
}

View file

@ -0,0 +1,11 @@
#
#=DESCRIPTION audit allow change_profile with name space with quotes
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> ":foo:/bin/foo",
}
/usr/bin/foo2 {
audit allow change_profile -> ":foo:/bin/ foo",
}

View file

@ -0,0 +1,24 @@
#
#=DESCRIPTION audit allow change_profile
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> /bin/*,
}
/usr/bin/foo2 {
audit allow change_profile -> /bin/**,
}
/usr/bin/foo3 {
audit allow change_profile -> /bin/?,
}
/usr/bin/foo4 {
audit allow change_profile -> /bin/[ab],
}
/usr/bin/foo5 {
audit allow change_profile -> /bin/[^ab],
}

View file

@ -0,0 +1,69 @@
#
#=DESCRIPTION audit allow change_profile to a hat
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> /bin/foo//bar,
}
/usr/bin/foo2 {
audit allow change_profile -> /bin/foo//ba*,
}
/usr/bin/foo3 {
audit allow change_profile -> /bin/foo//ba**,
}
/usr/bin/foo4 {
audit allow change_profile -> /bin/foo//ba?,
}
/usr/bin/foo5 {
audit allow change_profile -> /bin/foo//ba[ab],
}
/usr/bin/foo6 {
audit allow change_profile -> /bin/foo//ba[^ab],
}
/usr/bin/foo7 {
audit allow change_profile -> /bin/fo*//bar,
}
/usr/bin/foo8 {
audit allow change_profile -> /bin/fo**//bar,
}
/usr/bin/foo9 {
audit allow change_profile -> /bin/fo?//bar,
}
/usr/bin/foo10 {
audit allow change_profile -> /bin/fo[ab]//bar,
}
/usr/bin/foo11 {
audit allow change_profile -> /bin/fo[^ab]//bar,
}
/usr/bin/foo12 {
audit allow change_profile -> /bin/fo*//ba*,
}
/usr/bin/foo13 {
audit allow change_profile -> /bin/fo**//ba**,
}
/usr/bin/foo14 {
audit allow change_profile -> /bin/fo?//ba?,
}
/usr/bin/foo15 {
audit allow change_profile -> /bin/fo[ab]//ba[ab],
}
/usr/bin/foo16 {
audit allow change_profile -> /bin/fo[^ab]//ba[^ab],
}

View file

@ -0,0 +1,67 @@
#
#=DESCRIPTION audit allow change_profile with name space
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> :foo:/bin/foo,
}
/usr/bin/foo2 {
audit allow change_profile -> :foo:/bin/fo*,
}
/usr/bin/foo3 {
audit allow change_profile -> :foo:/bin/fo**,
}
/usr/bin/foo4 {
audit allow change_profile -> :foo:/bin/fo?,
}
/usr/bin/foo5 {
audit allow change_profile -> :foo:/bin/fo[ab],
}
/usr/bin/foo6 {
audit allow change_profile -> :foo:/bin/fo[^ab],
}
/usr/bin/foo7 {
audit allow change_profile -> :fo*:/bin/foo,
}
/usr/bin/foo8 {
audit allow change_profile -> :fo**:/bin/foo,
}
/usr/bin/foo9 {
audit allow change_profile -> :fo?:/bin/foo,
}
/usr/bin/foo10 {
audit allow change_profile -> :fo[ab]:/bin/foo,
}
/usr/bin/foo11 {
audit allow change_profile -> :fo[^ab]:/bin/foo,
}
/usr/bin/foo12 {
audit allow change_profile -> :fo*:/bin/fo*,
}
/usr/bin/foo13 {
audit allow change_profile -> :fo**:/bin/fo**,
}
/usr/bin/foo14 {
audit allow change_profile -> :fo?:/bin/fo?,
}
/usr/bin/foo15 {
audit allow change_profile -> :fo[ab]:/bin/fo[ab],
}
/usr/bin/foo16 {
audit allow change_profile -> :fo[^ab]:/bin/fo[^ab],
}

View file

@ -0,0 +1,51 @@
#
#=DESCRIPTION audit allow change_profile with a variable (LP: #390810)
#=EXRESULT PASS
#
@{LIBVIRT}="libvirt"
@{LIBVIRT_RE}="libvirt*"
/usr/bin/foo {
audit allow change_profile -> @{LIBVIRT}-fo*,
}
/usr/bin/foo2 {
audit allow change_profile -> @{LIBVIRT}-fo**,
}
/usr/bin/foo3 {
audit allow change_profile -> @{LIBVIRT}-fo[ab],
}
/usr/bin/foo4 {
audit allow change_profile -> @{LIBVIRT}-fo[^ab],
}
/usr/bin/foo5 {
audit allow change_profile -> @{LIBVIRT}-fo?,
}
/usr/bin/foo6 {
audit allow change_profile -> @{LIBVIRT_RE}-foo,
}
/usr/bin/foo7 {
audit allow change_profile -> @{LIBVIRT_RE}-fo*,
}
/usr/bin/foo8 {
audit allow change_profile -> @{LIBVIRT_RE}-fo**,
}
/usr/bin/foo9 {
audit allow change_profile -> @{LIBVIRT_RE}-fo?,
}
/usr/bin/foo10 {
audit allow change_profile -> @{LIBVIRT_RE}-fo[ab],
}
/usr/bin/foo11 {
audit allow change_profile -> @{LIBVIRT_RE}-fo[^ab],
}

View file

@ -0,0 +1,25 @@
#
#=DESCRIPTION audit allow change_profile with just res
#=EXRESULT PASS
#
/usr/bin/foo {
audit allow change_profile -> *,
}
/usr/bin/foo2 {
audit allow change_profile -> **,
}
/usr/bin/foo3 {
audit allow change_profile -> ?,
}
/usr/bin/foo4 {
audit allow change_profile -> [ab],
}
/usr/bin/foo5 {
audit allow change_profile -> [^ab],
}

Some files were not shown because too many files have changed in this diff Show more